在 TypeScript 中,普通枚举(非 const enum)的一个特点是它会生成反向映射。这意味着你不仅可以通过枚举的名字获取对应的数值,还可以通过数值反查到枚举的名字。
举个例子
假设我们有一个枚举:
enum Color {
Red, // 0
Green, // 1
Blue // 2
}
在编译后的 JavaScript 中,TypeScript 会生成类似下面的代码:
var Color;
(function (Color) {
Color[Color["Red"] = 0] = "Red";
Color[Color["Green"] = 1] = "Green";
Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {}));
这里发生了两件事:
- 正向映射:通过枚举名称获取数值。例如,
Color.Red
返回0
。 - 反向映射:通过数值获取枚举名称。例如,
Color[0]
返回"Red"
。
反向映射的作用
反向映射的优势在于你可以轻松地将数值转换回它们对应的枚举名称,这在调试、日志记录或者在某些业务场景中需要显示友好的名称时非常有用。
例如:
console.log(Color.Red); // 输出 0
console.log(Color[0]); // 输出 "Red"
总结
- 正向映射:
Color.Red
→0
- 反向映射:
Color[0]
→"Red"
这种双向映射机制只适用于数字枚举。如果是字符串枚举,TypeScript 不会生成反向映射,因为反向映射对于字符串来说没有意义。
与常量枚举(const enum)区别
在 TypeScript 中,普通枚举和常量枚举(const enum)有以下主要区别:
1. 编译后的输出
- 普通枚举:
编译后会生成一个实际的对象,包含正向和反向映射。
例如:
var Color;
(function (Color) {
Color[Color["Red"] = 0] = "Red";
Color[Color["Green"] = 1] = "Green";
Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {}));
这意味着你可以通过 Color.Red
得到 0
,也可以通过 Color[0]
得到 "Red"
。
- 常量枚举(const enum):
编译后不会生成实际的枚举对象。
所有对常量枚举成员的引用都直接被内联替换成对应的值。例如:
const enum Color {
Red,
Green,
Blue
}
let c = Color.Green;
编译后代码会直接变成:
let c = 1;
没有额外的对象和反向映射生成。
2. 反向映射
- 普通枚举:
自动生成反向映射,使得可以通过值查找名称(仅适用于数字枚举)。 - 常量枚举:
没有反向映射,因为编译器会直接将枚举成员内联,反向查找就没有意义。
3. 用途与性能
- 普通枚举:
如果需要在运行时使用枚举对象(例如调试或反向查找),普通枚举是合适的选择。但生成的代码体积稍大,因为需要创建完整的对象。 - 常量枚举:
如果仅仅是为了在编译时使用枚举值,并且不需要运行时的对象或反向映射,可以使用常量枚举。这样可以减少编译后的代码体积和运行时开销,因为枚举成员会被内联。
总结
- 普通枚举生成实际的对象,支持双向映射,适合需要运行时反向查找的场景。
- 常量枚举在编译后直接内联枚举值,没有生成实际对象和反向映射,适合追求代码体积优化且不需要运行时枚举对象的场景。