Archived post: posted sometime between 2016 and 2022.

filter undefined and null values from an array while still satisfying TypeScript's strict null checks.

In strict mode, TypeScript makes it illegal to assign an array of type (T | undefined) to an array of type T[] . This prevents bugs by preventing us from dotting into (de-referencing) an undefined object. It also poses a problem: how do we convince the compiler that it is okay to assign to T[] after we have removed all of the undefined array values?

The answer is a user-defined type guard .

Let's start with an example. We start with an array of type (Date | undefined)[] and then filter out all the undefined dates.

const items: (Date | undefined)[] = [new Date(), undefined];

// Type '(Date | undefined)[]' is not assignable to type 'Date[]'.
const definedItemsBad: Date[] = items
    .filter(item => typeof item !== 'undefined');

Even though we have filtered the array, the compiler cannot infer that the array has no undefined values.

Happily, a user-defined type-guard tells the compiler what we have done. In the following code, note that input is of type T | undefined | null instead of type any . That ensures that T captures only the defined part of the union type instead of capturing the whole union type of T | undefined | null . That is what lets our input is T type-guard tell the compiler that we have narrowed the type.

const isDefined = <T>(input: T | undefined | null): input is T => { 
    return typeof input !== 'undefined' && input !== null;
};

const definedItems: Date[] = items.filter(isDefined);

By way of explanation, here is the evolution from an inline, non-generic type-guard to the above finished product. For simplicity's sake, I have returned true instead of doing the actual check for undefined and null .

const definedItems1: Date[] = items.filter((input): input is Date => true);

const isDefinedDate = (input): input is Date => true;
const definedItems2: Date[] = items.filter(isDefinedDate);

const isDefinedGeneric = <T>(input: T | undefined | null): input is T => true;
const definedItems3: Date[] = items.filter(isDefinedGeneric);

Here it all is as a Fiddle .