Trong code frontend hiện đại, union of string literal thường là lựa chọn mặc định; enum chỉ giữ khi cần một namespace giá trị thật ở runtime.
type OrderStatus = 'pending' | 'paid' | 'shipped'
const ORDER_STATUSES = ['pending', 'paid', 'shipped'] as const
type Status = (typeof ORDER_STATUSES)[number] // suy ra union từ mảngVì sao ưu tiên union:
- Không sinh code runtime. enum (không phải const enum) biên dịch ra một object JavaScript, cộng thêm vào bundle.
- Giá trị chính là chuỗi, nên so sánh với dữ liệu từ API hay localStorage không cần map qua lại.
- Ghép thẳng với as const để vừa có union type vừa có mảng lặp được.
Khi nào enum vẫn hợp lý: cần lặp qua tất cả thành viên ở runtime, hoặc codebase backend/.NET/Java đã dùng enum và muốn thống nhất.
Bẫy cần biết: const enum bị cấm dưới isolatedModules (Babel, esbuild, SWC biên dịch từng file nên không nội tuyến được giá trị). Numeric enum còn cho phép gán số bất kỳ trong một số phiên bản cũ, làm mất tính an toàn — nếu buộc dùng enum thì chọn string enum.