TypeScript 枚举(Enums)详解
枚举消灭魔法值:字符串枚举、数字枚举、const 枚举的用法与取舍,以及"现代 TS 是否还需要 enum"的争议解析。
枚举把魔法值收拢为命名常量:enum Status { Active = 'ACTIVE', Inactive = 'INACTIVE' }——自文档化 + 编译期校验。现代替代:as const 对象 + 联合类型(与 JS 产物更亲和);enum 仍适合需要运行时对象的场景。
消灭魔法值
// 魔法值散落各处
if (status === 'ACTVIE') {} // 拼错了编译器不管
// 枚举:单一事实源
enum Status {
Active = 'ACTIVE',
Inactive = 'INACTIVE',
Pending = 'PENDING',
}
if (status === Status.Active) {} // 拼错编译报错
字符串枚举优先——日志与调试中可读,数字枚举(默认 0/1/2 自增)的可读性与序列化友好度都差。
const 枚举与树摇
const enum Direction { Up, Down }
const d = Direction.Up; // 编译后直接内联为 0——零运行时代码
const enum 产物内联——但与现代工具链(isolatedModules)冲突,多数现代项目指南建议避免。
现代替代:as const 方案
const Status = { Active: 'ACTIVE', Inactive: 'INACTIVE' } as const;
type Status = typeof Status[keyof typeof Status];
// 'ACTIVE' | 'INACTIVE'
与 enum 等价的类型安全,产物是普通 JS 对象——无运行时特殊性、tree-shaking 友好、与类型剥离工具链(tsx/esbuild)完全兼容。
选择建议
| 场景 | 选择 |
|---|---|
| 需要运行时枚举对象 + 经典模式 | enum |
| 现代工具链(tsx/原生 TS) | as const 方案 |
| 配置驱动、序列化交互 | as const 方案 |
常见问题(FAQ)
Q:enum 是"坏味道"吗?
不是——它是 TS 独有的运行时产物(与 JS 的语义差异),这在类型剥离时代成为摩擦点。as const 方案因此流行,但 enum 本身设计良好。
Q:数字枚举的反向映射?
数字枚举编译后有"值→名"的反向映射(Status[0] === 'Active')——少见但有用的特性,字符串枚举没有。
Q:switch 穷尽枚举?
配 never 检查(见本系列《never 与 公开资料未说明》)——枚举加成员时所有 switch 编译报错,防漏处理。
参考文档
本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。