TypeScript 是如何将 enum 转化为 JavaScript 的?

enum(枚举)是 TypeScript 中一个非常实用的语言特性,用于定义一组有名字的常量。它在 JavaScript 中并没有直接对应的原生语法,因此编译器需要将其转化为 JavaScript 可执行的形式。本文将介绍 TypeScript 中各种类型的 enum 是如何被转译成 JavaScript 代码的。


一、普通的数字枚举(Number Enum)

TypeScript 复制代码
enum Direction {
  Up,
  Down,
  Left,
  Right
}

编译后的 JavaScript(ES5)代码:

JavaScript 复制代码
var Direction;
(function (Direction) {
  Direction[Direction["Up"] = 0] = "Up";
  Direction[Direction["Down"] = 1] = "Down";
  Direction[Direction["Left"] = 2] = "Left";
  Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));

原理解析:

  • TypeScript 使用 立即调用函数表达式(IIFE) 创建一个对象 Direction
  • 枚举成员不仅有 从名称到数值 的映射,如 Direction.Up === 0
  • 还有 从数值到名称 的反向映射,如 Direction[0] === "Up"
  • 这就是所谓的 双向映射(Bidirectional Mapping)。

二、带初始值的枚举

TypeScript 复制代码
enum Status {
  Ok = 200,
  NotFound = 404,
  Error = 500
}

编译结果:

JavaScript 复制代码
var Status;
(function (Status) {
  Status[Status["Ok"] = 200] = "Ok";
  Status[Status["NotFound"] = 404] = "NotFound";
  Status[Status["Error"] = 500] = "Error";
})(Status || (Status = {}));
  • 如果第一个枚举成员提供了初始值,其余成员会自动递增(如果没有指定值)。
  • 不影响双向映射机制。

三、字符串枚举(String Enum)

TypeScript 复制代码
enum Color {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE"
}

编译结果:

JavaScript 复制代码
var Color;
(function (Color) {
  Color["Red"] = "RED";
  Color["Green"] = "GREEN";
  Color["Blue"] = "BLUE";
})(Color || (Color = {}));

注意:

  • 字符串枚举只生成 单向映射Color.Red === "RED"
  • 无法通过 Color["RED"] 获取 Red,也无法做反向映射。

四、Heterogeneous Enum(混合型枚举)

TypeScript 复制代码
enum Result {
  Yes = 1,
  No = "NO"
}

编译后:

JavaScript 复制代码
var Result;
(function (Result) {
  Result[Result["Yes"] = 1] = "Yes";
  Result["No"] = "NO";
})(Result || (Result = {}));
  • 混合型枚举不是很推荐使用;
  • 可能会导致代码混淆,尤其是需要一致性的时候。

五、常量枚举(const enum

TypeScript 复制代码
const enum Axis {
  X,
  Y,
  Z
}

const dir = Axis.X;

编译后的 JavaScript:

JavaScript 复制代码
var dir = 0 /* X */;

特点:

  • 不生成任何枚举对象代码
  • 所有对枚举成员的引用都被直接替换为对应的值;
  • 更适合性能敏感或体积敏感的场景;
  • 但是不能用于需要运行时访问枚举对象的情况。

六、如何查看枚举转译后的 JavaScript?------使用 TypeScript Playground

想要直观地查看 TypeScript 枚举是如何被编译为 JavaScript 的代码,可以使用 TypeScript 官方提供的在线工具 ------ Playground

访问地址:

👉 www.typescriptlang.org/play/

使用方法:

  1. 打开 Playground 页面;

  2. 在左侧编辑器中输入你的 TypeScript 枚举代码,例如:

TypeScript 复制代码
enum Direction {
  Up,
  Down,
  Left,
  Right
}
console.log(Direction)
  1. 右侧就会自动显示编译后的 JavaScript 代码,默认是 ES5 模式;

console.log(Direction)的输出如下图所示:

  1. 你还可以通过点击上方的 "TS Config" 下拉按钮,选择不同的目标版本(如 ES3、ES5、ES6);

  2. 如果你使用了 const enum,记得关闭 isolatedModules 或开启 preserveConstEnums 才能查看其替换行为。

小贴士:

  • Playground 是调试 TypeScript 特性最简单有效的方式;
  • 除了枚举,也适用于泛型、装饰器、类型推导等各种高级语法的编译分析;
  • 它还能分享代码片段,只需点击右上角的 "Share" 按钮,即可生成链接。

七、编译选项影响

  • 如果开启了 --preserveConstEnumsconst enum 会保留为实际的 JavaScript 枚举对象;
  • 如果关闭 --isolatedModules,可以使用 const enum
  • 编译为 ES6 时,枚举仍然是 var + IIFE 模式,并不会转化为 const + classMap 等。

八、小结

枚举类型 是否生成对象 是否支持反向映射 编译后体积
数字枚举 一般
字符串枚举 一般
const 枚举 ❌(直接替换) 最小

九、结语

TypeScript 的 enum 设计初衷是为了增强 JavaScript 的可读性和类型安全性,但它的转译方式也让我们理解了一个类型系统是如何在不支持这些语法的 JavaScript 上运行的。选择使用哪种枚举,应当根据运行时是否需要访问枚举值、是否需要反向映射、以及最终代码的体积要求进行权衡。

相关推荐
Nicholas68几秒前
Flutter动画框架之SingleTickerProviderStateMixin、TickerProvider、Ticker源码解析(三)
前端
豆豆(设计前端)9 分钟前
解决Vue页面黑底红字遮罩层报错:Unknown promise rejection reason (webpack-internal)
前端·vue.js·webpack
电筒34 分钟前
URL重定向需要多次encodeURIComponent
前端
程序员鱼皮37 分钟前
Stack Overflow,彻底凉了!
前端·后端·计算机·程序员·互联网
Nicholas681 小时前
Flutter动画框架之AnimationController源码解析(二)
前端
鹏程十八少1 小时前
2. Android 第三方框架 okhttp责任链模式的源码分析 深度解读二
前端
贵州数擎科技有限公司1 小时前
LangChain 快速构建你的第一个 LLM 应用
前端·后端
ze_juejin1 小时前
Mongoose 与 MongoDB 数据库教程
前端
FogLetter1 小时前
深入理解React的useLayoutEffect:解决UI"闪烁"问题的利器
前端·react.js
冰糖雪梨dd1 小时前
h() 函数
前端·javascript·vue.js