Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Що таке discriminated union і як перевірити вичерпність через never?

Discriminated union - об'єднання об'єктних типів зі спільним полем-літералом («дискримінантом»). Перевірка цього поля звужує тип до конкретного варіанта.

type RequestState =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: User[] }
  | { status: 'error'; error: string };

function render(state: RequestState) {
  switch (state.status) {
    case 'idle':
      return 'Натисніть «Завантажити»';
    case 'loading':
      return 'Завантаження...';
    case 'success':
      return `${state.data.length} користувачів`;   // data доступне лише тут
    case 'error':
      return `Помилка: ${state.error}`;
  }
}

Чому це краще за набір необов'язкових полів ({ loading?: boolean; data?: User[]; error?: string }): неможливі стани (одночасно data і error, loading і data) стають непредставлюваними на рівні типів.

Перевірка вичерпності: якщо додати новий варіант, компілятор має вказати всі місця, де його не обробили:

function assertNever(value: never): never {
  throw new Error(`Необроблений стан: ${JSON.stringify(value)}`);
}

switch (state.status) {
  // ...усі case
  default:
    return assertNever(state);
}

У default після всіх case тип state звузився до never. Додали { status: 'cancelled' } - тепер у default потрапляє цей варіант, і передати його в параметр типу never не можна: помилка компіляції саме там, де треба доробити.

Де застосовують: стани запитів і форм, події та повідомлення (Redux actions, WebSocket-повідомлення), результати операцій ({ ok: true; value } | { ok: false; error }).

Докладніше в документації: Discriminated unions

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання