David
David

Reputation: 2746

Flow (type) doesn't respect manual check I do for a class property

An example:

class MyClass {
  foo: ?string;
  constructor(foo) {
    this.foo = foo;
  }

  doSomething() {
    if (!this.foo) throw new Error();
    console.log('hi'); // if I comment this line, I get no errors!
    const myFoo: string = this.foo;
  }
}

I get the following error:

12: const myFoo: string = this.foo; ^ Cannot assign this.foo to myFoo because null or undefined 1 is incompatible with string [2].

You can see it live here.

As you can see, I do make sure that this.foo is set. However, if after the check, there is any code executed, although that code doesn't do anything, it ignores my check.

Upvotes: 0

Views: 66

Answers (2)

Dave Meehan
Dave Meehan

Reputation: 3211

This is caused by Flow's Refinement Validations

That also provides an example workaround.

Read only variables aren't necessarily immutable. For example, delete this.foo doesn't cause an error (which might be a bug in flow because it seems like a clear violation of the type, but is distinct from reassignment - bug report).

Upvotes: 1

loganfsmyth
loganfsmyth

Reputation: 161677

Flow does not allow this because as far as it is concerned, the console.log() call could change the value of this.foo, which is right. Flow could theoretically special-case console.log since it isn't like to have side-effects, but it could be any function call there really. If you want this to work you need to grab the value first, e.g.

doSomething() {
  const foo = this.foo;
  if (!foo) throw new Error();
  console.log('hi');
  const myFoo: string = foo;
}

or

doSomething() {
  if (!foo) throw new Error();
  const foo = this.foo;
  console.log('hi');
  const myFoo: string = foo;
}

since there is no way for the type of the foo variable to change since it isn't reassigned anywhere.

Upvotes: 1

Related Questions