Hey there!
It appears that flow is a bit overly aggressive in its treatment of null/undefined. In particular, it doesn't notice early returns (or perhaps mutual exclusivity) as a mechanism for guaranteeing "not null."
Here's an example:
interface Entity {
id: ID,
type: Type,
version: ?Version,
};
const changes = {};
function stage (before: ?Entity, after: ?Entity) {
if (!before && !after) {
return;
}
changes[before ? before.id : after.id] = {
before,
after
};
}
Flow errors on the reference to after.id, stating that:
You can see, however, that if either before or after is null/undefined, the other is necessarily NOT null/undefined.
Cheers,
Mike
Flow's refinement machinery is not designed to support cases like this. You can write your code slightly differently and Flow will happily follow along.
function stage (before: ?Entity, after: ?Entity) {
let id = null;
if (before != null) {
id = before.id;
}
else if (after != null) {
id = after.id;
}
if (id == null) return;
changes[id] = {
before,
after
};
}
Thanks for the reply and suggestion! I did end up refactoring to something similar, but left the issue open to document this unexpected (to me) behavior. It makes sense that this might require some pretty heavy logical inference that is currently outside the scope of flow. Hopefully this issue can help others surprised by this.