Об'єднання типів
Що таке об'єднання типів (Union Type)
Об'єднання типів - це тип, який може бути одним із кількох указаних варіантів.
У TypeScript об'єднання створюються через вертикальну риску |:
let value: string | number;Це означає:
valueможе бути або рядком, або числом, але нічим іншим.
Приклад 1. Найпростіше об'єднання
let id: string | number;
id = 42; // OK
id = "42"; // OK
id = true; // ПомилкаТак ти обмежуєш набір допустимих типів, але при цьому зберігаєш гнучкість.
Приклад 2. Об'єднання в параметрах функції
function printId(id: string | number) {
console.log("ID:", id);
}
printId(123); // OK
printId("abc"); // OKФункція приймає або рядок, або число, але нічого іншого.
Приклад 3. Не всі методи доступні при union
Коли TypeScript не може точно визначити тип під час виконання, він дозволяє лише спільні методи для всіх типів.
function printId(id: string | number) {
console.log(id.length); // Помилка - у number немає .length
}Рішення: звузити тип (type narrowing):
function printId(id: string | number) {
if (typeof id === "string") {
console.log("Довжина рядка:", id.length);
} else {
console.log("Число:", id.toFixed(2));
}
}Після перевірки
typeofTypeScript "розуміє", який конкретно тип використовується.
Приклад 4. Union усередині об'єктів
Можна об'єднувати різні форми об'єктів:
type User = { name: string; age: number };
type Admin = { name: string; permissions: string[] };
type Person = User | Admin;
const user1: Person = { name: "Tim", age: 25 }; // OK
const user2: Person = { name: "Alex", permissions: [] }; // OK
const user3: Person = { name: "Bob" }; // Помилка: age або permissions обов'язковіПриклад 5. Використання в switch (discriminated unions)
TypeScript особливо добре працює з об'єднаннями, якщо додати дискримінатор - спільне поле для розрізнення варіантів.
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number };
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.side ** 2;
}
}
area({ kind: "circle", radius: 10 }); // OKЦе називається дискриміноване об'єднання (discriminated union) - один із найпотужніших патернів у TS.
Приклад 6. Об'єднання літеральних типів
Можна створювати обмежені набори значень:
type Direction = "up" | "down" | "left" | "right";
let move: Direction;
move = "up"; // OK
move = "down"; // OK
move = "forward"; // ПомилкаДуже зручно для статусів, ролей, режимів тощо.
Приклад 7. Об'єднання з null і undefined
Типові приклади - змінні, які можуть бути невизначені:
let username: string | null = null;
function printName(name: string | undefined) {
if (name) {
console.log(name.toUpperCase());
}
}Такі об'єднання допомагають TypeScript захищати код від помилок "Cannot read property of null".
Приклад 8. Об'єднання з type alias та інтерфейсами
type Status = "loading" | "success" | "error";
type Response = { status: Status; data?: string };
function handleResponse(res: Response) {
if (res.status === "success") {
console.log(res.data);
}
}Union vs Intersection (| vs &)
| Оператор | Назва | Приклад | Значення |
|---|---|---|---|
| | Union (об'єднання) | A | B | об'єкт, який є або A, або B |
& | Intersection (перетин) | A & B | об'єкт, який є і A, і B одночасно |
Приклад відмінності:
type Dog = { bark: () => void };
type Cat = { meow: () => void };
type PetUnion = Dog | Cat; // або пес, або кіт
type PetBoth = Dog & Cat; // і те, і те (істота, що вміє гавкати і нявкати)Підсумок
| Концепція | Приклад |
|---|---|
| Простий union | string | number |
| Об'єднання об'єктів | {a: number} | {b: string} |
| Літеральні об'єднання | "on" | "off" |
| Дискримінований union | { kind: "circle" } | { kind: "square" } |
| Union з null/undefined | string | null |
Просте визначення:
Union (
|) - це "АБО" для типів.Змінна може бути одним із кількох типів, і TypeScript вимагає, щоб ти явно вказав, який саме використовується під час роботи.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.