Flow: Method argument inference based on class field/property

Created on 17 Oct 2018  路  5Comments  路  Source: facebook/flow

Hi,

// @flow
class A {
  x: number;

  constructor(x) {
    this.x = x;
  }
}
new A('hello');

Flow says the error is at this.x = x;. Could it instead infer from this line that x constructor parameter is of type number (since we explicitly stated that x field is a number) and complain about the line new A('hello'); ?

Am I missing something ?

Cheers

question

All 5 comments

Hi!

Because x in constructor(x) isn't annotated, Flow will try and infer the type of x based on the use of the function (in this case it's used when creating the class instance).

You're only ever calling it with a string in new A('hello'), so Flow infers constructor(x : string). If you were to add something like new A({}), Flow will now think that constructor( x : string | {||}).

I recommend explicitly annotating x in your constructor to get a better positioned error鈥攖his is also the more correct way of doing it (see below why):

~~~jsx
// @flow
class A {
x: number;

constructor(x : number) {
this.x = x;
}
}

new A('hello');
~~~

You can check this out on flow.org/try

Additionally, if you were to export the class, Flow would complain about the missing type annotation anyway:

~~~jsx
// @flow
export class A {
x: number;

constructor(x) {
this.x = x;
}
}
~~~

Link to the above example. If you add the correct type annotation, you will see the error go away.


Hope this clears things up!

Thanks for your reply. I understand that it works like this. I was more asking why it works like this : why the inference isn't going a step further and guesses the type annotation on the constructor by itself. Because the explicit typing of x in the class property declaration leaves no ambiguity.

why the inference isn't going a step further and guesses the type annotation on the constructor by itself.

Most languages don't do this unless there is special syntax for it (ie Crystal's shorthand initialize form). Even when they do, you still need to type initializer arguments (ie, C++'s member initializer lists).

Flow would have to make _assumptions_ about the way people write code, which might not be valid for some鈥攐r even most鈥攃ode.

In my experience, 1-1 mappings between properties and constructor arguments are generally rare.

Because the explicit typing of x in the class property declaration leaves no ambiguity

Your declaration allows writing to property what implies changing its type

Just don't leave constructors unannotated

@omninonsense Construction like you're describing isn't what this issue is requesting. The inference requested would mean making no assumptions about the way code is written except that the body of the constructor is correct. Based on the manner that the argument x is used in the body of the constructor, the most permissive type that x could have is number.

This issue is requesting type inference of the arguments of a function based on their usage in the function body, not that constructors infer their argument types based on property types. A perhaps more general example would be
```// @flow
function example(x) {
const cast: number = x;
return cast + 10;
}

example('hello');
```
flow.org/try.

Was this page helpful?
0 / 5 - 0 ratings