Union и литеральные типы
Union
Union (|) — тип, который означает «одно из нескольких»:
let id: string | number;
id = 'abc';
id = 42;
Функция с union:
function print(value: string | number) {
console.log(value);
}
Сужение типа
Чтобы использовать специфичные методы — нужно сузить тип:
function print(value: string | number) {
if (typeof value === 'string') {
console.log(value.toUpperCase());
} else {
console.log(value.toFixed(2));
}
}
typeof — один из способов сужения.
Литеральные типы
Тип — конкретное значение:
type Status = 'idle' | 'loading' | 'success' | 'error';
let status: Status = 'idle';
status = 'loading'; // ок
status = 'done'; // ошибка
Числовые литералы:
type Dice = 1 | 2 | 3 | 4 | 5 | 6;
const roll: Dice = 4;
Булевы:
type Yes = true;
Комбинация с объектами
type Button = {
variant: 'primary' | 'secondary' | 'danger';
size: 'sm' | 'md' | 'lg';
};
Discriminated unions
Мощный паттерн: union объектов с общим полем-дискриминатором:
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'square'; side: number }
| { kind: 'rectangle'; width: number; height: number };
Поле kind — дискриминатор. По нему TypeScript понимает, какой вариант используется:
function area(shape: Shape): number {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius ** 2;
case 'square':
return shape.side ** 2;
case 'rectangle':
return shape.width * shape.height;
}
}
В каждом case доступны только соответствующие поля.
Тип null и undefined
type User = {
name: string;
email: string | null;
};
if (user.email !== null) {
console.log(user.email.toLowerCase());
}
Exhaustive check
TypeScript следит, что все варианты обработаны:
function area(shape: Shape): number {
switch (shape.kind) {
case 'circle': return Math.PI * shape.radius ** 2;
case 'square': return shape.side ** 2;
case 'rectangle': return shape.width * shape.height;
default:
const _exhaustive: never = shape;
throw new Error('Unknown shape');
}
}
Если добавишь новый вариант в Shape и забудешь обработать — TypeScript выдаст ошибку.
Union vs enum
// Union — предпочтительно
status: 'idle' | 'loading' | 'success';
// Enum — старый подход
enum Status {
Idle = 'idle',
Loading = 'loading',
}
Union проще и не создаёт runtime-код.
Итоги
- Union
|— одно из нескольких typeofсужает тип- Литеральные типы — конкретные значения
- Discriminated unions — мощный паттерн
neverдля exhaustive check- Union предпочтительнее enum