← Назад к вопросам
В чем разница между Literal Types и Enum в TypeScript?
1.8 Middle🔥 172 комментариев
#JavaScript Core#TypeScript
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между Literal Types и Enum в TypeScript
Хотя оба используются для ограничения возможных значений переменной, они имеют существенные различия в реализации, производительности и поведении.
1. Literal Types
Определение: Конкретное значение переменной является её типом. Это ограничивает переменную принимать только одно точное значение.
// Простые literal types
type Status = 'pending' | 'success' | 'error';
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type Direction = 'up' | 'down' | 'left' | 'right';
// Использование
let currentStatus: Status = 'pending';
currentStatus = 'success'; // OK
currentStatus = 'loading'; // Error: Type '"loading"' is not assignable
// С числами
type StatusCode = 200 | 201 | 400 | 404 | 500;
let code: StatusCode = 200; // OK
code = 201; // OK
code = 202; // Error
Характеристики:
- Typescript-only конструкция (стирается при компиляции)
- Структурная типизация
- Никак не влияет на финальный JavaScript
- Нет runtime представления
// Скомпилированный JavaScript (TypeScript убирает типы)
let currentStatus = 'pending'; // просто переменная со строкой
2. Enum
Определение: Это специальная конструкция TypeScript, которая создает именованный набор констант. В отличие от Literal Types, Enum создает реальный объект в JavaScript.
// String Enum
enum Status {
Pending = 'pending',
Success = 'success',
Error = 'error'
}
// Использование
let currentStatus: Status = Status.Pending;
console.log(currentStatus); // 'pending'
// Numeric Enum
enum Direction {
Up = 0,
Down = 1,
Left = 2,
Right = 3
}
let dir: Direction = Direction.Up;
console.log(dir); // 0
// Enum без явных значений (по умолчанию число от 0)
enum Color {
Red, // 0
Green, // 1
Blue // 2
}
console.log(Color.Red); // 0
console.log(Color.Blue); // 2
Скомпилированный JavaScript (Enum создает реальный объект!):
// String Enum компилируется в объект
var Status;
(function (Status) {
Status["Pending"] = "pending";
Status["Success"] = "success";
Status["Error"] = "error";
})(Status || (Status = {}));
// Numeric Enum
var Direction;
(function (Direction) {
Direction[Direction["Up"] = 0] = "Up";
Direction[Direction["Down"] = 1] = "Down";
Direction[Direction["Left"] = 2] = "Left";
Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));
Ключевые различия
1. Существование в Runtime
// Literal Types - стирается полностью
type Status = 'pending' | 'success' | 'error';
console.log(typeof Status); // Error: 'Status' only refers to a type
// Enum - существует как реальный объект
enum Status {
Pending = 'pending',
Success = 'success'
}
console.log(typeof Status); // 'object'
console.log(Status); // { Pending: 'pending', Success: 'success' }
console.log(Status.Pending); // 'pending'
2. Размер Bundle
// Literal Types
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
function request(method: HttpMethod) {
// компилируется в обычную функцию без типов
}
// Скомпилированный JS - нет доп. кода
function request(method) {
// тело функции
}
// Enum - добавляет код в бандл
enum HttpMethod {
Get = 'GET',
Post = 'POST',
Put = 'PUT',
Delete = 'DELETE'
}
// Скомпилированный JS - много доп. кода для Enum
var HttpMethod;
(function (HttpMethod) {
HttpMethod["Get"] = "GET";
HttpMethod["Post"] = "POST";
HttpMethod["Put"] = "PUT";
HttpMethod["Delete"] = "DELETE";
})(HttpMethod || (HttpMethod = {}));
3. Обратная совместимость (reverse mapping)
// Numeric Enum - есть reverse mapping
enum Status {
Pending = 0,
Success = 1
}
console.log(Status[0]); // 'Pending' - можно получить название по числу!
console.log(Status.Pending); // 0
// String Enum - нет reverse mapping
enum Color {
Red = 'red',
Blue = 'blue'
}
console.log(Color['red']); // undefined
console.log(Color.Red); // 'red'
// Literal Types - обратная совместимость не нужна (это просто тип)
4. Использование как тип vs Использование как значение
// Literal Types - ТОЛЬКО тип
type Direction = 'up' | 'down';
const move = (dir: Direction) => {};
move('up'); // OK
// Enum - и тип И значение
enum Direction {
Up = 'up',
Down = 'down'
}
// Как тип
const move = (dir: Direction) => {};
// Как значение - можно передать сам Enum
move(Direction.Up); // OK
const myDir = Direction.Down;
// Можно проверить значения
const directions = [Direction.Up, Direction.Down];
5. Расширяемость
// Literal Types - строгие, нельзя расширить
type Status = 'pending' | 'success';
// Нельзя добавить еще значение позже
// Но можно создать новый тип объединением
type ExtendedStatus = Status | 'error';
// Enum - можно объявить несколько раз (ambient declaration)
enum Status {
Pending = 'pending'
}
// Позже в другом месте
enum Status {
Success = 'success'
}
// Результат: Status имеет обе значения
console.log(Status.Pending); // 'pending'
console.log(Status.Success); // 'success'
6. JSON сериализация
// Literal Types - сериализуются как обычные значения
type Status = 'pending' | 'success';
const user = {
name: 'John',
status: 'pending' as Status
};
JSON.stringify(user);
// {"name":"John","status":"pending"}
// Enum - может быть проблема с numeric enum
enum StatusCode {
OK = 200,
NotFound = 404
}
const response = {
code: StatusCode.OK
};
JSON.stringify(response);
// {"code":200} - это число, не текст!
// String Enum работает как обычно
enum Status {
Pending = 'pending',
Success = 'success'
}
const user = {
status: Status.Pending
};
JSON.stringify(user);
// {"status":"pending"}
Таблица сравнения
| Свойство | Literal Types | Enum |
|---|---|---|
| Существует в runtime | Нет | Да |
| Размер бандла | 0 доп. кода | +Размер объекта |
| Может быть значением | Нет (только тип) | Да (и тип и значение) |
| Reverse mapping | - | Да (для numeric) |
| Легко проверить значение | Нет extra кода | Есть Enum объект |
| Стирается при компиляции | Да | Нет |
| Можно расширить позже | С новым Union | Да, через redeclaration |
| Для JSON | Прямое значение | Может быть число |
Практические примеры выбора
// ИСПОЛЬЗУЙ LITERAL TYPES для:
// 1. Простых наборов значений
type ButtonVariant = 'primary' | 'secondary' | 'outline';
// 2. Когда значение не нужно в runtime
interface ButtonProps {
variant: 'primary' | 'secondary';
}
// 3. Когда нужно минимизировать бандл
type Environment = 'development' | 'staging' | 'production';
// 4. Объединение с другими типами
type FormStatus = 'idle' | 'loading' | 'success' | 'error';
type UserState = FormStatus | 'offline';
// ИСПОЛЬЗУЙ ENUM для:
// 1. Когда нужны именованные константы в коде
enum ApiStatus {
Ok = 200,
BadRequest = 400,
NotFound = 404
}
if (response.status === ApiStatus.Ok) { } // Понятнее чем === 200
// 2. Когда нужно итерировать по значениям
enum Colors {
Red = 'red',
Green = 'green',
Blue = 'blue'
}
// Можно получить все значения
Object.values(Colors); // ['red', 'green', 'blue']
// 3. При работе с старым кодом, где нужны runtime объекты
// 4. Когда важна обратная совместимость значений
Лучшие практики
Рекомендация современных подходов:
// ИЗБЕГАЙ numeric enum
enum Status {
Pending = 0, // Опасно: легко спутать с false
Success = 1
}
// ЛУЧШЕ
type Status = 'pending' | 'success' | 'error';
// ИЛИ если нужны константы
const Status = {
Pending: 'pending',
Success: 'success',
Error: 'error'
} as const;
type Status = typeof Status[keyof typeof Status];
// ИЛИ string enum если действительно нужен Enum
enum Status {
Pending = 'pending',
Success = 'success',
Error = 'error'
}
Заключение
- Literal Types предпочтительны в большинстве современных приложений (легче, меньше кода)
- Enum полезны когда нужны именованные константы и runtime доступ
- Для новых проектов рекомендуется использовать Literal Types как основной инструмент
- String Enum лучше чем Numeric Enum (безопаснее)
- Рассмотри использование const assertion как альтернативу Enum