(Tested with master, 0.33.0 and 0.29.0, via the REPL.)
A longer example:
/* @flow */
"use strict";
const abc: string = {}.foo;
const def: string = abc.concat("... is undefined"); // explodes at run-time
console.log(def);
(You can sub in the required type of abc
with number or a record structure, and it'll still happily accept the undefined
result.)
Yeah, this is a known issue and the cause is somewhat complicated.
Flow supports a common pattern in JS where objects are built up incrementally:
var o = {};
write(o);
read(o);
function write(o) {
o.foo = 0;
}
function read(o) {
(o.foo: number);
}
The above example shows how properties can be written and read far away from the initial variable declaration. To support this, Flow considers the object unsealed. When in this mode, Flow allows any read of a property, as long as it's compatible with the corresponding write.
However, if there is no corresponding write, there is nothing for the read to be incompatible with.
The solution here is to recognize when an unsealed object has properties that are read from, but never written to. Due to the design of Flow itself, there's no good place to insert this check currently. Eventually, the plan is to "write" an empty
type into any property that has no writes. empty
is incompatible with all uses, so we will emit an error.
I am working on a few changes that should expose the opportunity to add this check, so assigning myself here. Will update this issue when the fix lands.
Thanks for the explanation. 馃槉
Could this be covered with a lint rule that disallows the following 2 cases:
const obj = {}; // Illegal
{}.foo; // illegal
Most helpful comment
Yeah, this is a known issue and the cause is somewhat complicated.
Flow supports a common pattern in JS where objects are built up incrementally:
The above example shows how properties can be written and read far away from the initial variable declaration. To support this, Flow considers the object unsealed. When in this mode, Flow allows any read of a property, as long as it's compatible with the corresponding write.
However, if there is no corresponding write, there is nothing for the read to be incompatible with.
The solution here is to recognize when an unsealed object has properties that are read from, but never written to. Due to the design of Flow itself, there's no good place to insert this check currently. Eventually, the plan is to "write" an
empty
type into any property that has no writes.empty
is incompatible with all uses, so we will emit an error.I am working on a few changes that should expose the opportunity to add this check, so assigning myself here. Will update this issue when the fix lands.