I'm not sure what's going on here, but annotating the object makes it work properly, so maybe it's something to do with sealed vs unsealed objects. I'm still confused Flow only misses the error after the use of the && operator, though.
const inferred = {
x: '',
y: '',
};
const a = inferred.y1; // error, as expected
const b = inferred.x && inferred.y1; // no error?
const declared = {
x: ('': string),
y: ('': string),
};
const c = declared.x && declared.y1; // error
const d = declared.y1; // error
See Try Flow.
Flow is being a bit clever here. In the inferred case, since we know that inferred.x
is ''
, and thus definitely falsey, the inferred.y1
in inferred.x && inferred.y1
is unreachable and thus not an error.
Compare the following:
const o = {p:''};
o.p && o.q;
to
const o = {p:'non-empty'};
o.p && o.q;
In the latter we know that o.p
is truthy, so o.q
is reachable and we error.
Similarly, when o
has type {p:string}
, flow "forgets" that o.p
has the literal value ''
and thus can't statically determine whether o.p
is truthy or falsey and considers o.q
reachable as well.
Long story short, this is expected and sound behavior.
Ah, interesting. Here's the original context in which I encountered it, which explains why I think this might still be a problem:
import React from 'react';
class inferred extends React.Component {
state = {
x: '',
y: '',
};
handlePress() {
this.setState({x: 'truthy'});
}
render() {
const a = this.state.y1; // error, as expected
const b = this.state.x && this.state.y1; // no error?
}
}
In the above context, I think I should an error in one of the following places:
setState({x: 'truthy literal'})
this.state.x && this.state.y1
Ah, this is definitely a bug. We shouldn't assume that this.state.x is the literal string ''
here. Thanks for the report!