TypeScript: TypeScript 枚举 (enum)

最后更新:2026-08-26

枚举(enum)是 TypeScript 少数几个在运行时有表现的类型特性——它既是一种类型,也生成实际的 JavaScript 对象。

1. 数字枚举

(1) 基本语法

TYPESCRIPT
enum Direction {
  Up,       // 0(自动从0递增)
  Down,     // 1
  Left,     // 2
  Right     // 3
}

let dir: Direction = Direction.Up;
console.log(dir);                // 0
console.log(Direction[0]);       // "Up"(反向映射)

(2) 自定义初始值

TYPESCRIPT
enum Status {
  Active = 1,    // 1
  Inactive,      // 2(自动递增)
  Pending        // 3
}

enum HttpStatus {
  OK = 200,
  Moved = 301,
  BadRequest = 400,
  NotFound = 404,
  ServerError = 500
}

let code: HttpStatus = HttpStatus.OK;
console.log(code);  // 200

(3) 数字枚举的反向映射

数字枚举编译后会生成双向映射对象——既可以通过名取值,也可以通过值取名:

TYPESCRIPT
enum Role {
  Admin = 0,
  Editor = 1,
  Viewer = 2
}

// 正向映射:名 → 值
console.log(Role.Admin);   // 0

// 反向映射:值 → 名
console.log(Role[0]);      // "Admin"
console.log(Role[1]);      // "Editor"

编译后生成的 JavaScript:

JAVASCRIPT
var Role;
(function (Role) {
  Role[Role["Admin"] = 0] = "Admin";
  Role[Role["Editor"] = 1] = "Editor";
  Role[Role["Viewer"] = 2] = "Viewer";
})(Role || (Role = {}));

2. 字符串枚举

(1) 基本语法

字符串枚举的每个成员必须显式赋值——没有自动递增:

TYPESCRIPT
enum EventType {
  Click = "click",
  Change = "change",
  Submit = "submit",
  Focus = "focus"
}

let event: EventType = EventType.Click;
console.log(event);  // "click"

(2) 字符串枚举没有反向映射

TYPESCRIPT
enum Color {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE"
}

console.log(Color.Red);       // "RED"  ✅ 正向映射
// console.log(Color["RED"]); // undefined ❌ 字符串枚举没有反向映射
💡 原因: 数字枚举的值是数字,可以做对象键;字符串枚举的值是字符串,和对象键冲突,所以无法实现反向映射。

▶ 示例:用枚举定义订单状态

TYPESCRIPT
enum OrderStatus {
  Pending = "PENDING",
  Processing = "PROCESSING",
  Shipped = "SHIPPED",
  Delivered = "DELIVERED",
  Cancelled = "CANCELLED"
}

function getStatusLabel(status: OrderStatus): string {
  switch (status) {
    case OrderStatus.Pending: return "待处理";
    case OrderStatus.Processing: return "处理中";
    case OrderStatus.Shipped: return "已发货";
    case OrderStatus.Delivered: return "已送达";
    case OrderStatus.Cancelled: return "已取消";
  }
}

let currentStatus: OrderStatus = OrderStatus.Processing;
console.log(`当前状态:${getStatusLabel(currentStatus)}`);
console.log(`状态码:${currentStatus}`);
▶ 试一试

输出:

TEXT 📖 仅展示
当前状态:处理中
状态码:PROCESSING

3. 异构枚举

枚举可以混合数字和字符串值——但不推荐:

TYPESCRIPT
enum Mixed {
  No = 0,
  Yes = "YES"
}
⚠️ 不推荐: 异构枚举容易引起混淆,TypeScript 官方文档也建议避免使用。实际开发中,要么全用数字枚举,要么全用字符串枚举。


4. const 枚举

const enum 在编译时被内联替换——不生成 JavaScript 对象,性能更好但功能受限:

(1) 基本语法

TYPESCRIPT
const enum Color {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE"
}

let c = Color.Red;
// 编译后:let c = "RED"(直接内联替换,没有枚举对象)

(2) const 枚举的限制

TYPESCRIPT
const enum Direction {
  Up = "UP",
  Down = "DOWN"
}

// ❌ const 枚举不能使用反向映射
// console.log(Direction[0]);

// ❌ const 枚举不能在运行时遍历
// for (let d in Direction) { }

// ✅ 只能做简单的值引用
let dir = Direction.Up;  // 编译为 let dir = "UP"

(3) preserveConstEnums 选项

如果需要 const 枚举不内联但保留枚举对象,开启 preserveConstEnums: true

TYPESCRIPT
// tsconfig.json
// "preserveConstEnums": true

const enum Status {
  Active = 1
}

let s = Status.Active;
// 编译后:枚举对象仍然生成(但引用也会内联)

5. 枚举的运行时与类型安全

(1) 枚举作为类型

TYPESCRIPT
enum Role {
  Admin,
  Editor,
  Viewer
}

function checkAccess(role: Role): boolean {
  return role === Role.Admin || role === Role.Editor;
}

checkAccess(Role.Admin);   // ✅
checkAccess(0);            // ✅ 数字枚举接受数字值(但 ⚠️ 不推荐)
// checkAccess(99);        // ✅ 编译通过!任何数字都能通过——这是数字枚举的漏洞
🔥 数字枚举的陷阱: 数字枚举类型的变量可以接受任何数字——let r: Role = 99 是合法的。这是因为数字枚举的设计考虑了位标志(bit flags)。如果需要严格的值约束,用字符串枚举或字面量联合类型。

(2) 字符串枚举更安全

TYPESCRIPT
enum Role {
  Admin = "ADMIN",
  Editor = "EDITOR",
  Viewer = "VIEWER"
}

let r: Role = Role.Admin;   // ✅
// r = "ADMIN";             // ❌ 字符串枚举不接受普通字符串
// r = "SUPERADMIN";        // ❌ 只接受枚举成员

6. 枚举 vs 字面量联合类型

特性 枚举 字面量联合类型
运行时代码 有(生成对象) 无(纯类型)
反向映射 数字枚举有
遍历所有值 可以 不行
值约束 数字枚举较宽松 严格
代码提示 枚举成员自动提示 联合值自动提示
bundle 大小 增加代码体积 零体积
和 JS 互操作 枚举值是自定义对象 原生字符串/数字

(1) 用枚举的场景

(2) 用字面量联合类型的场景(推荐优先)

▶ 示例:两种方式对比

TYPESCRIPT
// 方式一:枚举
enum Direction1 {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

// 方式二:字面量联合类型(推荐)
type Direction2 = "UP" | "DOWN" | "LEFT" | "RIGHT";

// 两者在类型约束上等价
function move1(dir: Direction1): void { console.log(dir); }
function move2(dir: Direction2): void { console.log(dir); }

move1(Direction1.Up);  // ✅ "UP"
move2("UP");           // ✅ 直接用字符串,更简单

// 但枚举可以遍历
console.log(Object.values(Direction1));
// ["UP", "DOWN", "LEFT", "RIGHT"]

// 字面量联合类型无法遍历(纯编译时类型)
▶ 试一试

❓ 常见问题

Q 到底该不该用枚举?
A TypeScript 社区分两派——一派认为枚举是 TypeScript 的特色功能应该用,另一派认为字面量联合类型更轻量更推荐。实际建议:如果只需要类型约束(大多数情况),用字面量联合类型;如果需要运行时行为(遍历、反向映射),用枚举。
Q 数字枚举为什么能接受任意数字?
A 这是 TypeScript 的设计决策——数字枚举支持位标志(enum Perm { Read = 1, Write = 2, Execute = 4 }),位组合 Read | Write = 3 是合法的但不在枚举定义中。所以数字枚举类型放宽了约束。如果不想要这个行为,用字符串枚举或字面量联合类型。
Q const 枚举和普通枚举有什么区别?
A const 枚举在编译时内联替换——Color.Red 直接变成 "RED",不生成枚举对象。好处是 bundle 更小、运行时更快;缺点是不能反向映射、不能遍历、不能在动态场景使用。优先用 const 枚举(除非需要运行时特性)。
Q 枚举可以和接口/类型别名组合吗?
A 可以。枚举的值可以作为接口的属性类型——interface Config { role: Role }。枚举成员也可以作为联合类型成员——type Mixed = Role.Admin | "superadmin"。枚举是类型和值的统一体,用法灵活。

📖 小节

📝 作业

  1. 基础题(难度⭐):定义一个字符串枚举 Season(Spring/Summer/Autumn/Winter),写一个函数根据季节返回对应的月份范围描述。
  2. 进阶题(难度⭐⭐):用 const enum 定义 HTTP 方法(GET/POST/PUT/DELETE),然后定义一个 Request 接口包含 method 属性和 url 属性。创建几个请求对象验证类型约束。
  3. 挑战题(难度⭐⭐⭐):用字面量联合类型替代枚举,实现一个"权限系统":定义 Permission = "read" | "write" | "execute" | "admin",然后实现 hasPermission(userPerms: Permission[], required: Permission): boolean 函数,检查用户是否有指定权限(admin 拥有所有权限)。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏