六维教程

TypeScript 枚举

枚举是 TypeScript 为数不多的、JavaScript 中没有的特性。它让你用一组有名字的常量来代替散落在代码各处的「数字」或「字符串」。

先看一段没有枚举的代码:

function getOrderStatus(status: number): string {
  if (status === 0) return '待支付';
  if (status === 1) return '已支付';
  if (status === 2) return '已发货';
  if (status === 3) return '已完成';
  return '未知状态';
}

// 调用时:0 是什么意思?1 又是什么意思?
getOrderStatus(0);
getOrderStatus(1);

这段代码有两个问题:

  1. 可读性差012 这些数字含义不明。
  2. 容易出错:不小心传了 4 也能运行,但逻辑是错的。

用枚举改造后,这些问题迎刃而解:

enum OrderStatus {
  Pending = 0,   // 待支付
  Paid = 1,      // 已支付
  Shipped = 2,   // 已发货
  Completed = 3, // 已完成
}

function getOrderStatus(status: OrderStatus): string {
  switch (status) {
    case OrderStatus.Pending: return '待支付';
    case OrderStatus.Paid: return '已支付';
    case OrderStatus.Shipped: return '已发货';
    case OrderStatus.Completed: return '已完成';
    default: return '未知状态';
  }
}

// 调用:语义清晰,且只能传入枚举值
getOrderStatus(OrderStatus.Paid); // ✅ 清晰!
getOrderStatus(4); // ❌ 类型错误

枚举类型

数字枚举

数字枚举是默认类型,如果不给值,TypeScript 会自动从 0 开始递增:

// 不写值,默认从 0 开始
enum Direction {
  Up,    // 0
  Down,  // 1
  Left,  // 2
  Right, // 3
}

console.log(Direction.Up);    // 0
console.log(Direction.Down);  // 1

你也可以手动赋值:

enum Status {
  Pending = 1,
  Paid = 2,
  Shipped = 3,
  Completed = 4,
}

部分赋值时,后面的自动递增:

enum Status {
  Pending = 1, // 1
  Paid,        // 2(自动递增)
  Shipped,     // 3
  Completed = 10, // 10
  Archived,    // 11
}

反向映射

数字枚举支持反向映射——可以通过值反查出键名:

enum Direction {
  Up = 1,
  Down,
  Left,
  Right,
}

console.log(Direction[1]); // 'Up'
console.log(Direction.Down); // 2
console.log(Direction[2]); // 'Down'

这个特性是因为数字枚举编译后生成了对象,但字符串枚举没有反向映射,这个后面会讲。

字符串枚举

字符串枚举的每个值必须用字符串字面量赋值,没有自动递增:

enum Direction {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT',
}

console.log(Direction.Up); // 'UP'

什么时候用字符串枚举?

场景 推荐
API 返回的状态码('success' / 'error' ✅ 字符串枚举
需要日志可读性(看到的是英文单词而非数字) ✅ 字符串枚举
后端约定的是数字状态值 ✅ 数字枚举
需要做位运算或按位组合 ✅ 数字枚举

字符串枚举的优势是调试时日志更友好,但缺点是没有反向映射

enum Direction {
  Up = 'UP',
  Down = 'DOWN',
}

console.log(Direction.Up); // 'UP'
console.log(Direction['UP']); // ❌ 报错,字符串枚举不支持反向映射

异构枚举(不推荐)

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

enum Mixed {
  Up = 1,
  Down = 'DOWN', // 可以,但很怪
}

实用建议:保持统一,要么全数字,要么全字符串。

常量枚举

const 声明枚举,编译后会被完全移除,所有引用直接替换成具体的值:

const enum Direction {
  Up = 'UP',
  Down = 'DOWN',
}

console.log(Direction.Up);
// 编译后直接变成:
// console.log('UP');

为什么要用常量枚举?

  • 减少编译后的代码体积
  • 没有运行时对象,性能更优

注意事项:常量枚举只能使用字面量表达式,不能使用计算值。

枚举的实际使用场景

场景一:状态管理

enum OrderStatus {
  Pending = 'pending',
  Paid = 'paid',
  Shipped = 'shipped',
  Completed = 'completed',
}

// 根据状态渲染不同的 UI
function renderStatus(status: OrderStatus): string {
  const map = {
    [OrderStatus.Pending]: '🟡 待支付',
    [OrderStatus.Paid]: '🔵 已支付',
    [OrderStatus.Shipped]: '🟣 已发货',
    [OrderStatus.Completed]: '🟢 已完成',
  };
  return map[status] || '未知';
}

renderStatus(OrderStatus.Paid); // '🔵 已支付'

场景二:定义固定的选项列表

enum UserRole {
  Admin = 'admin',
  Editor = 'editor',
  Viewer = 'viewer',
}

function checkPermission(role: UserRole): boolean {
  return role === UserRole.Admin;
}

场景三:与类型注解配合

enum HttpMethod {
  GET = 'GET',
  POST = 'POST',
  PUT = 'PUT',
  DELETE = 'DELETE',
}

function request(url: string, method: HttpMethod): void {
  // 实现请求逻辑
}

request('/api/users', HttpMethod.GET); // ✅
request('/api/users', 'PATCH'); // ❌ 'PATCH' 不在枚举中
上一篇
TypeScript 数组与元组
下一篇
TypeScript 函数类型