Flow raises error when assigning `null` to a property of an interface but not to an equivalent variable

Viewed 382

Can someone explain why this works:

const foo: number | null = null;

And the following does not? For me they are the same, but Flow found some error.

interface Bar {
  foo: number | null;
}

const bar: Bar = {
  foo: null,
}
// Error
27:   foo: null,
           ^ Cannot assign object literal to `bar` because null [1] is incompatible with number [2] in property `foo`.
References:
27:   foo: null,
           ^ [1]
23:     foo: number | null;
             ^ [2]

Try Flow demo

1 Answers

According to the documentation, "interface properties are invariant by default." We can see that this results in an error if trying to assign an object literal to a typed variable,

interface Invariant { property: number | string }

var value1: Invariant = { property: 42 }; // Error!

Try Flow

However, the property can be modified after assignment,

interface Invariant { property: number | string }

function method1(value: Invariant) {
  value.property;        // Reading works!
  value.property = 3.14; // Writing works!
}

Try Flow

In your case, you could write

interface Bar { foo: number | null };

function method1(bar: Bar) {
  bar.foo = null;
}

Try Flow

You could also implement Bar for a class and assign the foo property

interface Bar { foo: number | null };

class X implements Bar {
  foo: number | null;

  constructor() {
    this.foo = null;
  }
}

Try Flow

Related