Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filtering an array of Maybe (nullable) types in Flow to remove null values

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.

like image 947
Robin Pokorny Avatar asked May 23 '17 09:05

Robin Pokorny


People also ask

How do you filter out null?

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.


1 Answers

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.

like image 51
Robin Pokorny Avatar answered Oct 29 '22 16:10

Robin Pokorny