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 complains 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.org/try.
Is there a way to tell flow that the array includes only non-nullable items now?
This destroys my functional JavaScript programming.
The most common filter syntax to filter out nulls is simply "-NULL" . This works for most data types that aren't numbers, such as strings, dates, etc.
Quick 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.org/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.org/try):
const baz = bar
.reduce((prev, next) => next == null ? prev : [...prev, next], [])
.map(({foo}) => foo);
However, this use case is so common 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.
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