Flow: Document "%checks" (Was: "if" condition type guard does not work when moved to function)

Created on 26 Aug 2017  Â·  22Comments  Â·  Source: facebook/flow

Description

I moved the boolean "if" condition into a function because it was pretty long. Without any other changes, this if-condition type guard is no longer recognized and Flow complains about using properties that that function checks exist.

After some experiments, I don't see a way to have a type guard be a function?

I understand the "mutability" assumption Flow makes whenever a function is called, but being unable to use a function as type guard, as seems to be the case, seems a little... severe. After all, functions starting with is...() (isBoolean, isThis, isThat, etc.) are quite common. I am unable to use a function in a type guard check?

Code

// @flow
'use strict';

function test1 () {
    // ERROR: Property 'myFn' cannot be assigned on 'data' (mixed)
    function isMyFunction (data: mixed): boolean {
        return typeof data === 'object' && data !== null && data.myFn === 'function';
    }

    function demo (data: mixed): void {
        if (isMyFunction(data)) {
            data.myFn = () => {
                // ...
            };
        }
    }
}

function test2 () {
    // WORKS
    function demo (data: mixed): void {
        if (typeof data === 'object' && data !== null && data.myFn === 'function') {
            data.myFn = () => {
                // ...
            };
        }
    }
}

Error

Error: src/main.js:11
 11:             data.myFn = () => {
                      ^^^^ property `myFn`. Property cannot be assigned on
 11:             data.myFn = () => {
                 ^^^^ mixed

Found 1 error

Working example

Flow Try link

Needs docs

Most helpful comment

UPDATE:

The check does not work when I move it into another file (module) and require() it from there. The exact same function!!

All 22 comments

Add %checks to your function annotation:

function isMyFunction (data: mixed): boolean %checks {

This leads to a question and a problem:

Question: Is this documented somewhere?

Problem: Since I'm not the only one who has never heard of that annotation Webstorm goes berserk (and all yellowish "I don't recognize what you are writing" background). Which leads back to the question - I don't want to file a Webstorm ticket for a feature that isn't documented.

I agree it should be documented, but to work around your problem you can do this:

```js
function isMyFunction (data: mixed)/*: boolean %checks */{

@vkurchatkin I changed the title, would you please reopen the issue and label it "documentation"? I think that's better than me opening another issue.

Could somebody tell me if %checks is official enough to open a Webstorm ticket to add this to the accepted syntax? Or is this just a workaround that some day may disappear.

UPDATE:

The check does not work when I move it into another file (module) and require() it from there. The exact same function!!

It's expected. Only type annotations passes through files. This makes flow fast. Passing additional information with %checks can solve the problem, but this is not implemented yet.

@TrySound There is a problem - so I opened an issue.

@TrySound I read that yesterday. I searched for "%checked" in the issues list. I refrained from linking it because it isn't about %checks in particular. I tried to limit the scope of my issue to that concrete item, since as you correctly point out there already is one for more general discussion.

@panagosg7 since you implemented this could you tell me how I would use %checks in a library definition? From the playground, looks like it's not possible at the moment. Could it be?

e.g.

declare module "lodash" {
  declare class Lodash {
      isString: (value: any): boolean %checks (typeof value === 'string');
  }

  declare var exports: Lodash;
}

function method(x: string | number): number {
  if (lodash.isString(x)) {
    return x.charCodeAt(0);
  } else {
    return x;
  }
}

I'm afraid function predicates (and the use of %checks modifier) are not supported for class methods at the moment.

@Whoaa512 if import the check function by name:

import {isString} from 'lodash';

function method(x: string | number): number {
  if (isString(x)) { .... }
}

It works for me.

@loyd Is that using the flow-typed declarations? or a custom one you wrote? Could you share that it looks like?

@Whoaa512

I have tried not with lodash, but the same case:
Declaration
Import
Usage

Thanks, my mistake =(

Do predicate functions work with instanceof I'm trying to implement a simple error handler with no luck frowtry. Or am I missing something else?

Hi @maxmalov! instanceof works. The problem in the above is the property access. Flow cannot refine properties of objects in predicate functions. Here's a workaround: try-flow

Checks is documented here.

I'm afraid function predicates (and the use of %checks modifier) are not supported for class methods at the moment.

@panagosg7 Do you know if function predicates support was added for class methods?

@akoppela No, class methods are still not supported.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bennoleslie picture bennoleslie  Â·  3Comments

funtaps picture funtaps  Â·  3Comments

jamiebuilds picture jamiebuilds  Â·  3Comments

ctrlplusb picture ctrlplusb  Â·  3Comments

marcelbeumer picture marcelbeumer  Â·  3Comments