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" 按钮,即可生成链接。

七、编译选项影响

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

八、小结

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

九、结语

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

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大3 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师3 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学3 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端