Typescript Array.filter(Boolean)

Out of the box, Typescript doesn’t play well with Array.filter(Boolean). There’s a lot of history to this issue and it hasn’t fully been fixed yet. In the below snippet, the returned type from the filter should be string[], but instead it’s (string | null | undefined)[].

const foo: (string | null | undefined)[] = [];
const bar: string[] = foo.filter(Boolean);
//    ^^^
// Type '(string | null | undefined)[]' is not assignable to type 'string[]'.

To fix the issue, you can add an overload to Array.prototype.filter() for the special case of using the boolean constructor as the predicate. Save the below snippet as lib.es5.d.ts:

/**
 * Fixes https://github.com/microsoft/TypeScript/issues/16655 for `Array.prototype.filter()`
 * For example, using the fix the type of `bar` is `string[]` in the below snippet as it should be.
 * 
 *  const foo: (string | null | undefined)[] = [];
 *  const bar = foo.filter(Boolean);
 * 
 * For related definitions, see https://github.com/microsoft/TypeScript/blob/master/src/lib/es5.d.ts
 * 
 * Original licenses apply, see
 *  - https://github.com/microsoft/TypeScript/blob/master/LICENSE.txt
 *  - https://stackoverflow.com/help/licensing
 */

/** See https://stackoverflow.com/a/51390763/1470607  */
type Falsy = false | 0 | "" | null | undefined;

interface Array<T> {
  /**
   * Returns the elements of an array that meet the condition specified in a callback function.
   * @param predicate A function that accepts up to three arguments. The filter method calls the predicate function one time for each element in the array.
   * @param thisArg An object to which the this keyword can refer in the predicate function. If thisArg is omitted, undefined is used as the this value.
   */
  filter<S extends T>(predicate: BooleanConstructor, thisArg?: any): Exclude<S, Falsy>[];
}

And then add it to your tsconfig as an include:

{
  "include": [
    "lib.es5.d.ts"
  ]
}