Skip to main content

Що означає "discriminated union"?

Що таке Discriminated Union

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

Простіше кажучи: це union, у всіх членів якого є спільна властивість, і за її значенням TypeScript розуміє, який саме тип перед нами.


Приклад 1. Проста форма дискримінованого об'єднання

javascript
type Shape = | { kind: "circle"; radius: number } | { kind: "square"; side: number }; function getArea(shape: Shape): number { if (shape.kind === "circle") { // Тут shape: { kind: "circle"; radius: number } return Math.PI * shape.radius ** 2; } else { // Тут shape: { kind: "square"; side: number } return shape.side ** 2; } }
  • Спільне поле kind - дискримінатор
  • TypeScript автоматично звужує тип залежно від його значення
  • Можна безпечно звертатися до radius чи side, без as і без помилок

Чому це зручно

У звичайних union-типах TS не знає, який саме об'єкт використовується:

javascript
type Circle = { radius: number }; type Square = { side: number }; type Shape = Circle | Square; function area(shape: Shape) { // shape.radius Помилка: у Square немає radius }

Якщо ж додати спільне поле (kind), TypeScript може сам здогадатися, хто є хто.


Приклад 2. Кілька варіантів типів

javascript
type Shape = | { kind: "circle"; radius: number } | { kind: "square"; side: number } | { kind: "triangle"; base: number; height: number }; function area(shape: Shape): number { switch (shape.kind) { case "circle": return Math.PI * shape.radius ** 2; case "square": return shape.side ** 2; case "triangle": return (shape.base * shape.height) / 2; } }

Усередині кожного case TypeScript точно знає, які поля доступні, і підказує їх в автодоповненні.


Приклад 3. Перевірка вичерпності (exhaustiveness check)

Дискриміновані union-и дозволяють контролювати, що всі можливі варіанти оброблено (важливо під час розширення типів):

javascript
function area(shape: Shape): number { switch (shape.kind) { case "circle": return Math.PI * shape.radius ** 2; case "square": return shape.side ** 2; case "triangle": return (shape.base * shape.height) / 2; default: // Помилка, якщо з'явиться новий тип без case const _exhaustiveCheck: never = shape; return _exhaustiveCheck; } }

Отже, якщо ти додаси новий тип (наприклад, "rectangle"), TS одразу покаже, що switch більше не покриває всі варіанти.


Приклад 4. Реальний сценарій (API-відповідь)

javascript
type ApiResponse = | { status: "success"; data: string } | { status: "error"; message: string } | { status: "loading" }; function handleResponse(res: ApiResponse) { switch (res.status) { case "success": console.log("Дані:", res.data); break; case "error": console.error("Помилка:", res.message); break; case "loading": console.log("Завантаження..."); break; } }

Один дискримінувальний ключ (status) повністю описує стан. Дуже популярний прийом у React-коді та Redux-логіці.


Правила дискримінованих union-типів

ВимогаОпис
Спільне поле (дискримінатор)Усі варіанти повинні мати одну й ту саму властивість (наприклад, kind, type, status)
Унікальні значенняКожне значення дискримінатора унікальне для свого варіанта
Тип поля - літеральнийЗазвичай це рядковий літерал ("circle", "error", "admin")
TS автоматично звужує типПеревірка if або switch виконує narrowing без кастів

Дискримінований union vs звичайний union

ВидПрикладTS може звузити тип автоматично?
Звичайний union{ radius: number } | { side: number }Ні
Дискримінований union{ kind: "circle" } | { kind: "square" }Так

Підсумок

ТермінЗначення
Discriminated unionОб'єднання типів зі спільним "дискримінувальним" полем
Навіщо потрібенЩоб TypeScript міг точно визначити тип за значенням поля
Як позначаєтьсяЧерез `
Головна перевагаБезпечне і зручне звуження типів без ручних перевірок
Типове застосуванняСтатуси, форми даних, API-відповіді, фігури, стани компонентів

Коротко:

Discriminated union - це об'єднання об'єктів, у яких є спільне поле-мітка (наприклад, kind), і за значенням цієї мітки TypeScript автоматично розуміє, який це тип

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.