TypeScript: Why is that my filter method cannot narrow the type and eliminate the undefined and false from the array

TypeScript’s standard library does have a signature for Array.prototype.filter() which will narrow the type of the array, but it will only use that signature if the compiler recognizes the passed-in callback as a type guard function whose return type is a type predicate of the form paramName is SomeType. And, unfortunately, the compiler is not currently able to infer that a callback (like Boolean or x => !!x) is a type guard; you have to annotate it as such.

(See microsoft/TypeScript#16069 for the feature request to use some sort of control flow analysis to interpret certain functions as type guards.)

Here’s one such annotated callback:

const truthyFilter = <T>(x: T | false | undefined | null | "" | 0): x is T => !!x;

or if you really want you can use Boolean as the implementation with a type assertion like

const truthyFilter2 = Boolean as any as <T>(x: T | false | undefined | null | "" | 0) => x is T;

That is sort of a generic truthiness detector, although TypeScript doesn’t really have a good way to represent all possible falsy values in the type system (NaN is unrepresentable for exaple). Anyway you can see it in action like this:

function fn(arr: Array<false | undefined | MyEvent>) {

  const item = arr[0];
  if (truthyFilter(item)) {
    item.eventDesc; // okay, no error
  }

And now if you use it with filter() the compiler will narrow it as expected:

  const myEvents = arr.filter(truthyFilter)
  // const myEvents: MyEvent[]

Okay, hope that helps; good luck!

Playground link

Leave a Comment