DEV Community

Chris Cook
Chris Cook

Posted on • Edited on • Originally published at zirkelc.dev

Array Filter: How to Filter Values With Correct Types

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

Top comments (1)

Collapse
 
niklampe profile image
Nik

Great article. 🙌 Needed to solve a similar problem just now.