Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript and filter Boolean

Tags:

Consider following code with strictNullChecks turned on:

var a: (number | null)[] = [0, 1, 2, 3, null, 4, 5, 6]; var b: { value: number; }[] = a.map(x => x != null && { value: x }).filter(Boolean); 

It fails to compile due to:

Type '(false | { value: number; })[]' is not assignable to type '{ value: number; }[]'.   Type 'false | { value: number; }' is not assignable to type '{ value: number; }'.     Type 'false' is not assignable to type '{ value: number; }'. 

But it is absolutely clear, that false will be filtered away by .filter(Boolean).

Same problem with null.

Is there a way (except writing as number[]) to mark that value doesn't contain false or null?

like image 377
Qwertiy Avatar asked Dec 04 '17 11:12

Qwertiy


People also ask

What is filter Boolean I typescript?

filter(Boolean as any as ExcludesFalse); This works because you are asserting that Boolean is a type guard, and because Array. filter() is overloaded to return a narrowed array if the callback is a type guard.

What does filter Boolean mean?

filter(Boolean)` just removes values from a list which are "falsey", like empty strings or null.

What does filter Boolean do in Javascript?

The filter(Boolean) step does the following: Passes each item in the array to the Boolean() object. The Boolean() object coerces each item to true or false depending on whether it's truthy or falsy. If the item is truthy, we keep it.

What does filter do in typescript?

In Typescript, Filter() is a built-in array method which is defined as a method for creating a new array or set of elements that contains a subset of the given array elements by returning the array of all the values of the elements in the newly created sub-array over the given array.


2 Answers

You can use functions like this

function nonNullable<T>(value: T): value is NonNullable<T> {   return value !== null && value !== undefined; }  type Truthy<T> = T extends false | '' | 0 | null | undefined ? never : T; // from lodash  function truthy<T>(value: T): value is Truthy<T> {     return !!value; }  [1, 2, 0, null].filter(nonNullable) // number[] [1, 2, 0, null].filter(truthy) // number[] 

NonNullable - https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#predefined-conditional-types

like image 134
justerest Avatar answered Sep 20 '22 13:09

justerest


If you really don't want to change the generated JavaScript, and instead prefer to force the TypeScript compiler to recognize that Boolean is serving as a guard against false values, you can do this:

type ExcludesFalse = <T>(x: T | false) => x is T;      var b: { value: number; }[] = a   .map(x => x != null && { value: x })   .filter(Boolean as any as ExcludesFalse); 

This works because you are asserting that Boolean is a type guard, and because Array.filter() is overloaded to return a narrowed array if the callback is a type guard.

The above (Boolean as any as ExcludesFalse) is the cleanest code I could come up with that both works and doesn't change the generated JavaScript. The constant Boolean is declared to be an instance of the global BooleanConstructor interface, and you can merge an ExcludesFalse-like type guard signature into BooleanConstructor, but not in a way that allows you to just say .filter(Boolean) and have it work. You can get fancier with the type guard and try to represent guarding against all falsy values (except NaN) but you don't need that for your example.

Anyway, hope that helps; good luck!

like image 36
jcalz Avatar answered Sep 19 '22 13:09

jcalz