This code passes the flow check:
/* @flow */
function test (list: ?Array<string>): Promise<number> {
if(list !== null && list !== undefined) {
return Promise.resolve(list.length)
} else {
return Promise.resolve(0)
}
}
console.log(test(null))
Whereas the following gets a null check error
/* @flow */
function test (list: ?Array<string>): Promise<number> {
if(list !== null && list !== undefined) {
return Promise.resolve().then(() => list.length)
} else {
return Promise.resolve(0)
}
}
console.log(test(null))
error:
property `length`. Property cannot be accessed on possibly null value
Clearly list cannot be null
so there must be something about the code structure that makes flow unable to recognise this.
I would like to understand what limitation I am hitting and how I can work around it. Thanks!
Basically, Flow doesn't know that your type refinement (null check) will hold at the time when () => list.length
is executed. Inside that callback Flow only looks at the type of list – which says it can be null.
The difference between first and second snippet is that in the second snippet list
is crossing a function boundary – you're using it in a different function than where you refined its type.
One solution is to extract list.length into a variable, and use that variable in the callback.
var length = list.length;
return Promise.resolve().then(() => length)
This might also work:
var list2: Array<string> = list;
return Promise.resolve().then(() => list2.length)
Note that this problem exists even for immediately invoked callbacks, e.g. when using map
or forEach
. There is an issue on flow's github about this, but I couldn't find it after a quick search.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With