Що означає "discriminated union"?
Що таке Discriminated Union
Discriminated union - це об'єднання (union) кількох типів об'єктів,
де в кожному типі є спільне поле-мітка (дискримінатор),
яке однозначно вказує, до якого варіанта належить об'єкт.
Простіше кажучи: це union, у всіх членів якого є спільна властивість, і за її значенням TypeScript розуміє, який саме тип перед нами.
Приклад 1. Проста форма дискримінованого об'єднання
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 не знає, який саме об'єкт використовується:
type Circle = { radius: number };
type Square = { side: number };
type Shape = Circle | Square;
function area(shape: Shape) {
// shape.radius Помилка: у Square немає radius
}Якщо ж додати спільне поле (kind), TypeScript може сам здогадатися, хто є хто.
Приклад 2. Кілька варіантів типів
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-и дозволяють контролювати, що всі можливі варіанти оброблено (важливо під час розширення типів):
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-відповідь)
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 автоматично розуміє, який це тип
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.