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 上运行的。选择使用哪种枚举,应当根据运行时是否需要访问枚举值、是否需要反向映射、以及最终代码的体积要求进行权衡。

相关推荐
InlaidHarp几秒前
Elpis DSL领域模型设计理念
前端
lichenyang4532 分钟前
react-route-dom@6
前端
番茄比较犟4 分钟前
widget的同级移动
前端
每天吃饭的羊8 分钟前
面试题-函数入参为interface类型进行约束
前端
屋外雨大,惊蛰出没32 分钟前
Vue+spring boot前后端分离项目搭建---小白入门
前端·vue.js·spring boot
梦语花36 分钟前
如何在前端项目中优雅地实现异步请求重试机制
前端
彬师傅39 分钟前
JSAPITHREE-自定义瓦片服务加载
前端·javascript
番茄比较犟42 分钟前
UI更新中Widget比较过程
前端
独立开发者Pony43 分钟前
关于我用 Ai 完成了一套系统 99% 代码这件事
前端·javascript·github
番茄比较犟1 小时前
Widget位置移动详细
前端