Array Filter: How to Filter Values With Correct Types

Chris Cook - Nov 4 '22 - - Dev Community

TypeScript doesn't infer the return type of an array filter operation in the same way that it does for an if statement to check whether a variable is defined.

Let's consider the following example:

type User = {
  id: number;
  name?: string;
};

const listUsers = (): User[] => {
  // fetch users from some API and return them
  return [];
};

// names will be of type (string | undefined)[]
const names = listUsers()
  .map((user) => user.name)
  .filter((name) => !!name);
Enter fullscreen mode Exit fullscreen mode

The type of names is inferred by TypeScript as (string | undefined)[], although we explicitly filter out falsy values. TypeScript somehow doesn't interpret the condition inside the filter function.

To get TypeScript to infer the return type correctly, we need to use a custom type-guard.

// type-guard to assure name is a string
const filterNames = (name?: string): name is string => {
  return !!name;
}

const names = listUsers()
  .map((user) => user.name)
  .filter(filterNames);
Enter fullscreen mode Exit fullscreen mode

The return type name is string of this type-guard function will assure TypeScript that we have checked the type and can safely treat it as string.

However, if we don't want to define a separate filter function, we can also use the type guard inside the inline filter function:

const names = listUsers()
  .map((user) => user.name)
  .filter((name?: string): name is string => !!name);
Enter fullscreen mode Exit fullscreen mode
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player