Что такое тип `never` в TypeScript?

MiddleTypeScript · Frontend·Обновлено 9 августа 2026
Коротко
Тип never представляет значения, которые никогда не могут существовать — он используется для функций, которые никогда не возвращают управление (бросают исключение или уходят в бесконечный цикл), и как результат невозможных пересечений типов.

Тип never в TypeScript

Тип never — это нижний тип (bottom type) в системе типов TypeScript. Он означает «значение, которое никогда не может существовать». В отличие от void, который говорит «функция ничего не возвращает», never говорит «функция никогда не завершится нормально».

Основные случаи использования

1. Функции, которые никогда не возвращают управление

Функция, которая всегда бросает исключение или содержит бесконечный цикл, имеет возвращаемый тип never:

function throwError(message: string): never {
  throw new Error(message);
}

function infiniteLoop(): never {
  while (true) {
    // бесконечный цикл
  }
}

2. Исчерпывающая проверка (exhaustiveness check)

Один из самых важных паттернов — гарантировать, что все ветки switch или if-else обработаны. Если компилятор допускает присвоение значения переменной типа never, значит, ветка достижима и что-то не так:

type Shape = 'circle' | 'square' | 'triangle';

function getArea(shape: Shape): number {
  switch (shape) {
    case 'circle':
      return Math.PI;
    case 'square':
      return 1;
    case 'triangle':
      return 0.5;
    default:
      // Если сюда дошли — значит добавили новый тип в Shape, но забыли обработать
      const exhaustiveCheck: never = shape;
      throw new Error(`Неизвестная фигура: ${exhaustiveCheck}`);
  }
}

Теперь, если добавить 'pentagon' в тип Shape без обновления switch, TypeScript выдаст ошибку компиляции.

3. Невозможные пересечения типов

Когда пересечение типов не может содержать ни одного значения, TypeScript выводит never:

type Impossible = string & number; // never

type OnlyAdmin = { role: 'admin' } & { role: 'user' }; // never

4. Фильтрация типов через conditional types

never активно используется в утилитарных типах для фильтрации:

// Исключаем из объединения определённые типы
type NonNullable<T> = T extends null | undefined ? never : T;

// Оставляем только строковые ключи
type StringKeys<T> = {
  [K in keyof T]: T[K] extends string ? K : never;
}[keyof T];

type User = { name: string; age: number; email: string };
type StringUserKeys = StringKeys<User>; // 'name' | 'email'

never vs void vs unknown

Тип Смысл
void Функция завершилась, но без значения
never Функция никогда не завершится
unknown Значение есть, но тип неизвестен

Поведение в объединениях и пересечениях

never ведёт себя как нейтральный элемент:

  • В объединении never исчезает: string | neverstring
  • В пересечении never поглощает всё: string & nevernever

Это свойство делает never фундаментальным строительным блоком для создания сложных conditional types.

Что хочет услышать интервьюер

Понимание, что `never` — нижний тип, значения которого не могут существовать во время выполнения

Знание двух ключевых сценариев: функции без возврата (throw/infinite loop) и исчерпывающие проверки в switch

Умение отличить `never` от `void` — особенно важно для middle-разработчика

Практическое применение в conditional types и дженериках для фильтрации типов

Понимание поведения `never` в объединениях (исчезает) и пересечениях (поглощает)

Пример: Основные сценарии использования never

// Функция, которая никогда не возвращает управление
function fail(message: string): never {
  throw new Error(message);
}

// Exhaustiveness check — защита от забытых кейсов
type Status = 'active' | 'inactive' | 'banned';

function handleStatus(status: Status): string {
  switch (status) {
    case 'active':
      return 'Пользователь активен';
    case 'inactive':
      return 'Пользователь неактивен';
    case 'banned':
      return 'Пользователь заблокирован';
    default:
      // Если добавить новый статус в тип Status —
      // TypeScript выдаст ошибку именно здесь
      const _exhaustive: never = status;
      return fail(`Необработанный статус: ${_exhaustive}`);
  }
}

Пример: never в дженериках и conditional types

// never в conditional types — фильтрация ключей объекта
type PickByValue<T, V> = {
  [K in keyof T]: T[K] extends V ? K : never;
}[keyof T];

interface Product {
  id: number;
  name: string;
  price: number;
  description: string;
}

// Получаем только строковые поля
type StringFields = PickByValue<Product, string>;
// Результат: 'name' | 'description'

// never исчезает в объединениях
type Result = string | never; // string
// never поглощает в пересечениях
type Impossible = string & never; // never

Типичные ошибки

Путают `never` и `void` — считают, что обе означают «нет возвращаемого значения»

Не знают про exhaustiveness check — самое практически ценное применение `never`

Думают, что `never` можно присвоить переменной с реальным значением

Не понимают, почему `never` исчезает в объединениях типов

Считают `never` экзотикой без практической пользы, не зная про conditional types

Лучшие курсы по теме

изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Feature-Sliced Design

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее