TypeScript 枚举类型在运行时的表现
TypeScript 中的枚举虽然在开发阶段提供了类型安全,但在编译成 JavaScript 后,它们的行为并非完全一致。理解枚举在运行时的具体表现,有助于避免潜在的 bug 并优化打包体积。
1. 数字枚举与双向映射
数字枚举是 TypeScript 中最基础的枚举形式。当你在代码中定义一个数字枚举时,TypeScript 编译器会生成一个真正的 JavaScript 对象。这个对象不仅包含成员名到值的映射,还包含值到成员名的反向映射。
定义 一个名为 Status 的数字枚举:
enum Status {
Pending,
Success,
Error
}
编译 上述代码,查看生成的 JavaScript 代码:
var Status;
(function (Status) {
Status[Status["Pending"] = 0] = "Pending";
Status[Status["Success"] = 1] = "Success";
Status[Status["Error"] = 2] = "Error";
})(Status || (Status = {}));
观察 这段生成的代码,执行 Status[0] 会得到字符串 "Pending",而 Status["Pending"] 会得到数字 0。
注意 这种双向映射会导致运行时代码体积增加,并且如果不小心遍历枚举对象,可能会同时遍历出键名和数字键。
2. 字符串枚举的单向映射
与数字枚举不同,字符串枚举在运行时不会生成反向映射。这意味着生成的 JavaScript 对象更轻量,且行为更符合常规对象的直觉。
定义 一个名为 Direction 的字符串枚举:
enum Direction {
Up = "UP_VALUE",
Down = "DOWN_VALUE"
}
编译 上述代码,查看生成的 JavaScript 代码:
var Direction;
(function (Direction) {
Direction["Up"] = "UP_VALUE";
Direction["Down"] = "DOWN_VALUE";
})(Direction || (Direction = {}));
尝试 访问 Direction["UP_VALUE"],结果会是 undefined。
使用 字符串枚举可以有效地避免因为反向映射带来的混淆,适用于只需要通过键名获取值的场景。
3. 常量枚举的编译期内联
常量枚举使用 const enum 关键字定义。它们是 TypeScript 提供的一种优化手段,在编译阶段会被完全移除,所有使用到枚举值的地方都会被直接替换为具体的常量值。
定义 一个名为 ConstantStatus 的常量枚举:
const enum ConstantStatus {
Ready,
Set,
Go
}
编写 调用代码:
const currentStatus = ConstantStatus.Ready;
编译 后查看生成的 JavaScript 代码:
var currentStatus = 0 /* ConstantStatus.Ready */;
观察 运行时环境中并不存在 ConstantStatus 这个对象。如果你在运行时需要动态获取枚举的键名(例如 ConstantStatus[0]),这种方式会报错。
注意 使用常量枚举可以显著减少运行时的代码体积,但必须确保不需要在运行时动态访问枚举对象本身。
4. 外部枚举与声明合并
外部枚举使用 declare enum 定义,通常用于描述已经存在于其他地方的枚举类型(例如在 .d.ts 声明文件中)。编译器默认不会为它们生成任何代码。
定义 一个外部枚举:
declare enum AmbientEnum {
A = 1,
B = 2
}
使用 该枚举:
const val = AmbientEnum.A;
编译 后的代码中,AmbientEnum.A 不会被替换为 1,而是保留原样 AmbientEnum.A。这意味着你必须确保在运行时,全局作用域或引入的库中已经定义了 AmbientEnum 变量,否则代码会在运行时报错。
5. 枚举类型对比总结
为了更直观地理解不同枚举在运行时的差异,请参考下表。
| 枚举类型 | 关键字 | 运行时产物 | 反向映射 | 适用场景 |
|---|---|---|---|---|
| 数字枚举 | enum |
真实 JavaScript 对象 (IIFE) | 是 | 需要通过值获取键名,或用于位运算 |
| 字符串枚举 | enum |
真实 JavaScript 对象 (IIFE) | 否 | 需要明确的字符串值,关注代码可读性 |
| 常量枚举 | const enum |
无 (代码内联) | 无 | 追求极致性能,不需要运行时对象 |
| 外部枚举 | declare enum |
无 (保留引用) | 取决于外部实现 | 声明第三方库或全局环境的类型 |

暂无评论,快来抢沙发吧!