as const и Enum
as constиenum— два подхода к созданию именованных констант в TypeScript:enumсоздаёт рантайм-объект и тип одновременно,as constфиксирует литеральные типы обычного объекта без генерации дополнительного кода.
Зачем нужно
Перечисления нужны для ограниченного набора допустимых значений (статусы, роли, направления). enum — встроенный механизм, но он создаёт рантайм-объект и имеет неочевидное поведение. as const с объектом — современная альтернатива без сюрпризов.
Где используется
- Статусы сущностей:
PENDING | ACTIVE | INACTIVE - Роли пользователей:
ADMIN | USER | GUEST - Направления, HTTP-методы, коды ошибок
- Константы конфигурации
Основной контент
Numeric enum
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right, // 3
}
function move(dir: Direction): void {
console.log(dir); // 0, 1, 2 или 3
}
move(Direction.Up); // OK
// move(0); // OK! TypeScript принимает число — неожиданно
// Reverse mapping: Direction[0] === "Up"
console.log(Direction[Direction.Up]); // "Up"
String enum
enum Status {
Pending = "PENDING",
Active = "ACTIVE",
Inactive = "INACTIVE",
}
function updateStatus(s: Status): void { /* ... */ }
updateStatus(Status.Active); // OK
// updateStatus("ACTIVE"); // Error — нужен именно Status.Active
as const объект — современная альтернатива
const Direction = {
Up: "UP",
Down: "DOWN",
Left: "LEFT",
Right: "RIGHT",
} as const;
// Тип значений:
type Direction = typeof Direction[keyof typeof Direction];
// "UP" | "DOWN" | "LEFT" | "RIGHT"
function move(dir: Direction): void {
console.log(dir);
}
move(Direction.Up); // OK
move("UP"); // OK — строка совместима с literal type
move("diagonal"); // Error
Сравнение: enum vs as const
// Enum — рантайм объект, компилируется в JS
enum Color { Red = "RED", Green = "GREEN", Blue = "BLUE" }
// Компилируется в:
// var Color;
// Color["Red"] = "RED"; Color["Green"] = "GREEN"; ...
// as const — только тип, никакого рантайм-кода кроме объекта
const Color = { Red: "RED", Green: "GREEN", Blue: "BLUE" } as const;
// Компилируется в:
// const Color = { Red: "RED", Green: "GREEN", Blue: "BLUE" };
const enum — inlined значения
const enum HttpMethod {
Get = "GET",
Post = "POST",
Put = "PUT",
Delete = "DELETE",
}
// TypeScript inlines значения при компиляции:
const method = HttpMethod.Get;
// → const method = "GET"; (объект не создаётся)
// Ограничение: const enum нельзя использовать в другом пакете
// (при isolatedModules: true)
Когда что выбирать
// Выбирайте as const если:
// - Нужна совместимость со строковыми литералами
// - Хотите минимальный рантайм код
// - Работаете с bundler и isolatedModules
const ROLES = { Admin: "admin", User: "user", Guest: "guest" } as const;
type Role = typeof ROLES[keyof typeof ROLES]; // "admin" | "user" | "guest"
// Выбирайте enum если:
// - Нужен reverse mapping (Direction[0] === "Up")
// - Команда привыкла к enum из C#/Java
// - Нужна строгая изоляция (string enum)
Частые ошибки
- Numeric enum принимает произвольные числа —
move(42)не вызовет ошибку при numeric enum; string enum строже. - Ambient enum в isolatedModules —
const enumнесовместим сisolatedModules: true; используйте regular enum или as const. - Забыть
as const— без него TypeScript расширяет тип полей доstring, а не"admin" | "user". - Смешивать enum и string — значение
Status.Activeи"ACTIVE"несовместимы при string enum; нужно явное сравнение.