首页 / TypeScript 入门教程 / 枚举(enum)

TypeScript 入门教程

枚举(enum)

本教程共 80 篇 · 第 12 篇 · 更新于 2026-08-10 · 约 12 分钟阅读

TypeScriptTypeScript 入门教程枚举enumconst enum

本节目标:理解枚举是什么、什么时候用,掌握数字枚举和字符串枚举的用法,了解 const enum 的优化效果和官方立场,学会用联合字面量类型替代枚举。

枚举解决什么问题

写代码时经常要处理一组固定的常量——比如方向只有上下左右、订单状态只有待付款/已付款/已发货。用原始字符串或数字可以直接写,但容易出错:

// JavaScript 的写法:容易拼错
function move(direction: string) {
  if (direction === "up") { /* ... */ }
}

move("Up");   // 大小写错了,静默失败
move("upp");  // 打错字了,静默失败

枚举把一组相关常量聚合成一个有名字的集合,让你用成员名代替裸值:

enum Direction {
  Up,
  Down,
  Left,
  Right
}

function move(direction: Direction) {
  // direction 只能是 Direction 的成员
}

move(Direction.Up);     // ✅ 编译器保证不会拼错
// move("Up");          // ❌ 字符串 "Up" 不是 Direction 类型
Note

枚举是 TypeScript 少数几个不是纯类型层面的特性——它会产生运行时代码。这一点我们后面展开讲。

数字枚举

最简单的枚举。不赋值时,成员从 0 开始自动递增:

enum Color {
  Red,    // 0
  Green,  // 1
  Blue    // 2
}

console.log(Color.Red);   // 0
console.log(Color.Green); // 1
console.log(Color.Blue);  // 2

你也可以手动指定起始值,后续继续自动递增:

enum Status {
  Success = 1,
  Error,      // 2
  Pending     // 3
}

console.log(Status.Pending);  // 3

每个成员单独赋值也没问题:

enum HttpStatus {
  OK = 200,
  NotFound = 404,
  InternalError = 500
}

// 也可以使用计算值
enum FileAccess {
  Read = 1 << 1,       // 2
  Write = 1 << 2,      // 4
  ReadWrite = Read | Write  // 6
}

反向映射

数字枚举有个特殊行为:可以从值反查键名

enum Direction {
  Up,    // 0
  Down,  // 1
  Left,  // 2
  Right  // 3
}

console.log(Direction[0]);  // "Up"
console.log(Direction[2]);  // "Left"

编译成 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 = {}));

就是一个双向绑定的对象。反向映射在调试时很方便——打印数字就能看到对应的名称。

Note

反向映射只有数字枚举支持。字符串枚举没有反向映射。

字符串枚举

字符串枚举每个成员都必须显式赋值,成员值是字符串而非数字:

enum Message {
  Success = "SUCCESS",
  Error = "ERROR",
  Warning = "WARNING"
}

function handleMessage(msg: Message) {
  switch (msg) {
    case Message.Success:
      console.log("操作成功");
      break;
    case Message.Error:
      console.log("操作失败");
      break;
    case Message.Warning:
      console.log("警告");
      break;
  }
}

handleMessage(Message.Success);  // "操作成功"

字符串枚举的优点是可读性好——Message.Success 值就是 "SUCCESS",日志里看到这个字符串能一眼认出来。缺点是没有反向映射,也不支持自动递增。

实际项目中字符串枚举比数字枚举更常见,因为日志和网络传输时字符串比数字好理解。

异构枚举:数字和字符串混用

枚举里可以混合数字和字符串,但强烈不推荐

enum Mixed {
  No = 0,
  Yes = "YES"
}
// 能跑通,但没人这么写——混淆了两种语义

计算成员 vs 常量成员

枚举成员分为两种:

常量成员:编译时就能确定值——包括字面量、对其他常量枚举成员的引用、常量表达式:

enum E {
  A = 1,            // 常量
  B = 1 + 2,        // 常量(常量表达式)
  C = Math.random()  // 计算成员(运行时才知道值)
}

计算成员没有反向映射能力,而且会让整个枚举变成”非 const”(不能用于 const enum 优化)。

const enum 和内部优化

在枚举前加 const 关键字,TypeScript 会把所有引用内联到代码里,完全消除运行时的枚举对象:

const enum Direction {
  Up,
  Down,
  Left,
  Right
}

let dir = Direction.Up;
// 编译后 → let dir = 0 /* Direction.Up */;

编译后的 JavaScript 中,Direction 对象不复存在,所有引用被替换成了字面量。这减少了代码体积和运行时开销。

🔴 关于 const enum 的官方立场

TypeScript 官方不推荐使用 const enum,该特性在未来版本可能被移除。

原因主要有两个:首先,const enum 的内联行为在跨项目导入时会出问题——如果使用方和定义方的枚举值不一致,类型检查可能漏出错。其次,Go 移植后的 7.0 编译器对 const enum 的支持有限,截至 7.0.2,官方尚未给出明确的 const enum 移除时间表。

// ❌ 官方不推荐
const enum Status {
  Active,
  Inactive
}

// ✅ 推荐替代:联合字面量类型
type Status = "active" | "inactive";

简单说:新项目不要引入 const enum。老项目中如果已经用了,留意官方后续动态。

用联合字面量类型替代枚举

枚举的很多场景可以用更轻量的联合字面量类型替代:

// 枚举写法
enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}
function move(dir: Direction) { }

// 联合字面量写法(推荐)
type Direction2 = "UP" | "DOWN" | "LEFT" | "RIGHT";
function move2(dir: Direction2) { }

move2("UP");  // ✅ 编辑器自动补全
// move2("upp");  // ❌ 编译错误

联合字面量的优势:

  • 不产生运行时代码
  • 更简洁,不需要 import
  • 编辑器同样提供自动补全
  • 完全类型安全

字符串枚举也不是一无是处——如果值需要在多处引用、或者需要遍历所有成员(Object.values(Status)),枚举仍然方便。

可运行示例

// 枚举综合示例

// 1. 数字枚举:订单状态
enum OrderStatus {
  Pending = 0,
  Paid = 1,
  Shipped = 2,
  Delivered = 3,
  Canceled = 4
}

function getStatusText(status: OrderStatus): string {
  switch (status) {
    case OrderStatus.Pending:   return "待付款";
    case OrderStatus.Paid:      return "已付款";
    case OrderStatus.Shipped:   return "已发货";
    case OrderStatus.Delivered: return "已签收";
    case OrderStatus.Canceled:  return "已取消";
  }
}

let order1 = OrderStatus.Paid;
console.log(`订单状态: ${getStatusText(order1)}`);
// 反向映射
console.log(`状态码 ${order1} 对应: ${OrderStatus[order1]}`);

// 2. 字符串枚举:日志级别
enum LogLevel {
  Debug = "DEBUG",
  Info = "INFO",
  Warn = "WARN",
  Error = "ERROR"
}

function log(level: LogLevel, message: string) {
  console.log(`[${level}] ${message}`);
}

log(LogLevel.Info, "服务启动成功");
log(LogLevel.Error, "数据库连接失败");

// 3. 联合字面量:替代枚举的推荐方式
type Theme = "light" | "dark" | "auto";

function applyTheme(theme: Theme) {
  console.log(`应用主题: ${theme}`);
}

applyTheme("dark");
// applyTheme("blue");  // ❌ 编译错误

输出:

订单状态: 已付款
状态码 1 对应: Paid
[INFO] 服务启动成功
[ERROR] 数据库连接失败
应用主题: dark

小结

枚举是 TypeScript 提供的一种聚合常量的机制。数字枚举支持反向映射,字符串枚举可读性更好。const enum 能减少代码体积但官方不推荐,新项目优先考虑联合字面量类型替代枚举。没有绝对的对错——小型项目或跨模块常量用联合字面量更清爽,需要遍历成员或频繁引用时枚举仍然是个好选择。下一章我们来看 anyunknown,以及它们对类型安全的不同影响。