TypeScript не выводит возвращаемый тип операции фильтра массива так же, как он делает это для оператора if, чтобы проверить, определена ли переменная.

Рассмотрим следующий пример:

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);
Войти в полноэкранный режим

Выйти из полноэкранного режима

Тип names выводится TypeScript как (string | undefined)[], хотя мы явно отфильтровываем ложные значения. TypeScript почему-то не интерпретирует условие внутри функции фильтра.

Чтобы TypeScript правильно определял возвращаемый тип, нам нужно использовать пользовательский типгард.

// 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);
Войти в полноэкранный режим

Выйти из полноэкранного режима

Тип возвращаемого значения name is string этой функции защиты типа будет гарантировать TypeScript, что мы проверили тип и можем безопасно обрабатывать его как string.

Однако, если мы не хотим определять отдельную функцию фильтра, мы также можем использовать защиту типа внутри функции встроенного фильтра:

const names = listUsers()
  .map((user) => user.name)
  .filter((name?: string): name is string => !!name);
Войти в полноэкранный режим

Выйти из полноэкранного режима