Если вы откроете крупный коммерческий проект на TypeScript, то с высокой вероятностью найдете там конструкции вроде
enum Status { Active, Inactive }. Долгое время это считалось хорошим тоном, но сегодня использование Enums это скорее антипаттерн, от которого индустрия постепенно отказывается.Почему «перечисления» ломают логику TypeScript и чем их заменить, чтобы код оставался чистым и предсказуемым.
1. Они генерируют лишний код в рантайме (Runtime Overhead)
TypeScript — это надстройка, которая после компиляции полностью исчезает, оставляя чистый JavaScript. Почти все фичи TS (интерфейсы, типы) весят 0 байт в бандле.
Но только не
enum. Посмотрим, во что превращается обычный enum после компиляции:
// TypeScript
enum Role {
Admin,
User
}
// JavaScript (после компиляции)
var Role;
(function (Role) {
Role[Role["Admin"] = 0] = "Admin";
Role[Role["User"] = 1] = "User";
})(Role || (Role = {}));
Вместо удаления типов компилятор создает громоздкую самовызывающуюся функцию и объект с двунаправленным маппингом (`Role.Admin` равен
0, а Role[0] равен `"Admin"`). В коммерческих проектах на сотни тысяч строк кода это раздувает бандл буквально на ровном месте.2. Дыры в безопасности (Numeric Enums)
Числовые enum'ы в TS удивительно нестрогие. Вы можете передать в функцию число, которого вообще нет в перечислении, и компилятор не выдаст ошибку:
enum Status {
Pending,
Success
}
function setStatus(status: Status) { ... }
// Ошибки нет, хотя статуса 99 не существует!
setStatus(99);
Современная альтернатива: Union Types +
as constЧтобы сохранить все преимущества автодополнения (IntelliSense) и строгости, но не тащить в рантайт лишний JS-код, используют связку обычного объекта и типов:
// 1. Создаем чистый объект с флагом "только для чтения"
const PROJECT_STATUS = {
PENDING: 'pending',
SUCCESS: 'success',
FAILED: 'failed',
} as const;
// 2. Генерируем тип из значений этого объекта
type ProjectStatus = typeof PROJECT_STATUS[keyof typeof PROJECT_STATUS];
// Тип равен: 'pending' | 'success' | 'failed'
// 3. Используем в коде
function updateStatus(status: ProjectStatus) { ... }
updateStatus(PROJECT_STATUS.SUCCESS); // Идеально
updateStatus('unknown'); // Ошибка компиляции
Что мы получаем в итоге?
1. Чистый JS: После компиляции остается только лаконичный плоский объект
PROJECT_STATUS. Никаких странных функций.2. Абсолютная строгость: Передать левое значение или число мимо типа физически невозможно.
3. Удобный рефакторинг: Названия ключей и значений меняются в один клик по всему проекту.
#typescript #полезнаястатья
