I have an array of Maybe (nullable) type, I want to filter those null
's to have an array containing only non-null values:
@flow
type Foo = {
foo: string
}
const bar: Array<?Foo> = [ null, { foo: 'Qux' } ]
const baz = bar
.filter(x => x != null)
.map(({ foo }) => foo);
However, flow plains that the argument can be still null
, while it clearly cannot:
11: .map(({ foo }) => foo);
^ property `foo`. Property cannot be accessed on possibly null value
See the code on flow/try.
Is there a way to tell flow that the array includes only non-nullable items now?
This destroys my functional JavaScript programming.
I have an array of Maybe (nullable) type, I want to filter those null
's to have an array containing only non-null values:
@flow
type Foo = {
foo: string
}
const bar: Array<?Foo> = [ null, { foo: 'Qux' } ]
const baz = bar
.filter(x => x != null)
.map(({ foo }) => foo);
However, flow plains that the argument can be still null
, while it clearly cannot:
11: .map(({ foo }) => foo);
^ property `foo`. Property cannot be accessed on possibly null value
See the code on flow/try.
Is there a way to tell flow that the array includes only non-nullable items now?
This destroys my functional JavaScript programming.
Share Improve this question asked May 23, 2017 at 9:55 Robin PokornyRobin Pokorny 10.7k1 gold badge25 silver badges32 bronze badges1 Answer
Reset to default 12Quick answer
Use .filter(Boolean)
to filter null
's.
const baz = bar
.filter(Boolean) // <- This is the trick
.map(({ foo }) => foo);
Check it passing on flow/try.
Explanation (sort of)
It is difficult for flow to understand what happens in the filter
callback, how the result was obtained, and if really all null
values were removed. Therefore it assumes that the type of array is the same after filtering; which in fact is correct, it can only be a subset of the array and hence a subset of the type.
In contrast, because of the way it works, reduce
creates a totally different structure for which type has to be inferred (flow/try):
const baz = bar
.reduce((prev, next) => next == null ? prev : [...prev, next], [])
.map(({foo}) => foo);
However, this use case is so mon that flow includes an exception in its code:
filter(callbackfn: typeof Boolean): Array<$NonMaybeType<T>>;
filter(callbackfn: (value: T, index: number, array: $ReadOnlyArray<T>) => any, thisArg?: any): Array<T>;
That means, that if (and only if) Boolean
is passed as the callback the resulting array will have type Array<$NonMaybeType<T>>
. Boolean
will surely remove null
(and undefined
) and can be trusted.