TypeScript枚举 #

一、枚举基础 #

1.1 什么是枚举 #

枚举(Enum)是TypeScript的一种特殊类型,用于定义一组命名的常量。枚举使代码更易读、更易维护。

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

let dir: Direction = Direction.Up;
console.log(dir);

1.2 枚举的作用 #

  • 为一组相关值提供友好的名称
  • 提高代码可读性
  • 避免使用"魔法数字"
  • 提供类型安全

二、数字枚举 #

2.1 基本数字枚举 #

数字枚举的值默认从0开始递增:

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

console.log(Direction.Up);
console.log(Direction.Down);
console.log(Direction.Left);
console.log(Direction.Right);

2.2 自定义数值 #

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

console.log(Direction.Up);
console.log(Direction.Down);
console.log(Direction.Left);
console.log(Direction.Right);

2.3 全部自定义 #

typescript
enum Direction {
    Up = 1,
    Down = 2,
    Left = 5,
    Right = 10
}

console.log(Direction.Up);
console.log(Direction.Down);
console.log(Direction.Left);
console.log(Direction.Right);

2.4 使用表达式 #

typescript
enum FileAccess {
    None = 0,
    Read = 1 << 0,
    Write = 1 << 1,
    ReadWrite = Read | Write,
    All = ~None
}

console.log(FileAccess.Read);
console.log(FileAccess.Write);
console.log(FileAccess.ReadWrite);

2.5 反向映射 #

数字枚举支持反向映射,可以通过值获取名称:

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

console.log(Direction.Up);
console.log(Direction[0]);
console.log(Direction[Direction.Up]);

编译后的JavaScript:

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

三、字符串枚举 #

3.1 基本字符串枚举 #

字符串枚举的每个成员都需要显式初始化:

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

console.log(Direction.Up);
console.log(Direction.Down);

3.2 字符串枚举特点 #

  • 没有自增行为
  • 不支持反向映射
  • 更好的可读性
typescript
enum HttpStatus {
    OK = '200 OK',
    NotFound = '404 Not Found',
    ServerError = '500 Internal Server Error'
}

function handleResponse(status: HttpStatus): void {
    console.log(`Response: ${status}`);
}

handleResponse(HttpStatus.OK);

3.3 实际应用 #

typescript
enum Environment {
    Development = 'development',
    Staging = 'staging',
    Production = 'production'
}

const config = {
    [Environment.Development]: {
        apiUrl: 'http://localhost:3000'
    },
    [Environment.Staging]: {
        apiUrl: 'https://staging.example.com'
    },
    [Environment.Production]: {
        apiUrl: 'https://api.example.com'
    }
};

const env = Environment.Development;
console.log(config[env].apiUrl);

四、异构枚举 #

4.1 什么是异构枚举 #

异构枚举混合了数字和字符串成员:

typescript
enum BooleanEnum {
    No = 0,
    Yes = 'YES'
}

console.log(BooleanEnum.No);
console.log(BooleanEnum.Yes);

4.2 不推荐使用 #

异构枚举容易造成混淆,通常不推荐使用:

typescript
enum BadPractice {
    A = 0,
    B = 'hello',
    C = 1,
    D = 'world'
}

五、const枚举 #

5.1 什么是const枚举 #

const枚举在编译时会被内联,不会生成额外的JavaScript代码:

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

let dir = Direction.Up;

编译后:

javascript
var dir = 0;

5.2 const枚举的优势 #

  • 更小的输出代码
  • 更好的性能
  • 没有运行时开销

5.3 使用场景 #

typescript
const enum HttpStatusCode {
    OK = 200,
    NotFound = 404,
    ServerError = 500
}

function handleStatus(code: HttpStatusCode): string {
    switch (code) {
        case HttpStatusCode.OK:
            return 'Success';
        case HttpStatusCode.NotFound:
            return 'Not Found';
        case HttpStatusCode.ServerError:
            return 'Server Error';
    }
}

5.4 preserveConstEnums选项 #

设置preserveConstEnums为true时,会保留枚举对象:

typescript
const enum Direction {
    Up,
    Down
}

编译后:

javascript
var Direction;
(function (Direction) {
    Direction[Direction["Up"] = 0] = "Up";
    Direction[Direction["Down"] = 1] = "Down";
})(Direction || (Direction = {}));

六、枚举成员 #

6.1 常量成员 #

常量成员在编译时就能确定值:

typescript
enum E {
    A = 0,
    B = 1 << 0,
    C = 1 + 2,
    D = A + B
}

6.2 计算成员 #

计算成员在运行时才能确定值:

typescript
enum E {
    A = Math.random(),
    B = 'hello'.length,
    C = Date.now()
}

6.3 成员类型 #

typescript
enum E {
    A,
    B = 1,
    C = 'hello'
}

type A = E.A;
type B = E.B;
type C = E.C;

let a: E.A = E.A;
let b: E.B = E.B;

七、联合枚举类型 #

7.1 枚举作为联合类型 #

typescript
enum Status {
    Pending,
    Approved,
    Rejected
}

function handleStatus(status: Status): void {
    console.log(`Status: ${status}`);
}

handleStatus(Status.Pending);
handleStatus(0);
handleStatus(100);

7.2 枚举成员作为类型 #

typescript
enum ShapeKind {
    Circle,
    Square,
    Triangle
}

interface Circle {
    kind: ShapeKind.Circle;
    radius: number;
}

interface Square {
    kind: ShapeKind.Square;
    sideLength: number;
}

let circle: Circle = {
    kind: ShapeKind.Circle,
    radius: 10
};

circle.kind = ShapeKind.Square;

八、运行时枚举 #

8.1 枚举是真实对象 #

枚举在运行时是真实存在的对象:

typescript
enum E {
    A, B, C
}

function f(obj: { A: number }): void {
    console.log(obj.A);
}

f(E);

8.2 遍历枚举 #

typescript
enum Color {
    Red = 'RED',
    Green = 'GREEN',
    Blue = 'BLUE'
}

for (const key in Color) {
    console.log(key);
}

Object.keys(Color).forEach(key => {
    console.log(`${key}: ${Color[key as keyof typeof Color]}`);
});

8.3 获取枚举值列表 #

typescript
enum Direction {
    Up = 1,
    Down = 2,
    Left = 3,
    Right = 4
}

const values = Object.values(Direction).filter(v => typeof v === 'number') as Direction[];
console.log(values);

const keys = Object.keys(Direction).filter(k => isNaN(Number(k)));
console.log(keys);

九、枚举与类型安全 #

9.1 类型安全的枚举参数 #

typescript
enum UserRole {
    Admin = 'ADMIN',
    User = 'USER',
    Guest = 'GUEST'
}

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

checkPermission(UserRole.Admin);
checkPermission('ADMIN');

9.2 字符串枚举的类型安全 #

typescript
enum Status {
    Active = 'ACTIVE',
    Inactive = 'INACTIVE'
}

function setStatus(status: Status): void {
    console.log(`Status set to: ${status}`);
}

setStatus(Status.Active);
setStatus('ACTIVE');

十、枚举最佳实践 #

10.1 使用const枚举优化性能 #

typescript
const enum Priority {
    Low = 1,
    Medium = 2,
    High = 3
}

function process(priority: Priority): void {
    console.log(`Processing with priority: ${priority}`);
}

process(Priority.High);

10.2 使用字符串枚举提高可读性 #

typescript
enum LogLevel {
    Debug = 'DEBUG',
    Info = 'INFO',
    Warn = 'WARN',
    Error = 'ERROR'
}

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

log(LogLevel.Info, 'Application started');

10.3 避免异构枚举 #

typescript
enum Bad {
    A = 0,
    B = 'hello'
}

enum Good {
    A = 'A',
    B = 'B'
}

10.4 使用枚举代替魔法数字 #

typescript
function process(status: number): void {
    if (status === 0) {
        console.log('Pending');
    } else if (status === 1) {
        console.log('Approved');
    }
}

enum Status {
    Pending = 0,
    Approved = 1,
    Rejected = 2
}

function processBetter(status: Status): void {
    if (status === Status.Pending) {
        console.log('Pending');
    } else if (status === Status.Approved) {
        console.log('Approved');
    }
}

十一、枚举替代方案 #

11.1 使用联合类型 #

typescript
type Direction = 'up' | 'down' | 'left' | 'right';

function move(dir: Direction): void {
    console.log(`Moving ${dir}`);
}

move('up');

11.2 使用对象常量 #

typescript
const Direction = {
    Up: 'UP',
    Down: 'DOWN',
    Left: 'LEFT',
    Right: 'RIGHT'
} as const;

type Direction = typeof Direction[keyof typeof Direction];

function move(dir: Direction): void {
    console.log(`Moving ${dir}`);
}

move(Direction.Up);

11.3 选择建议 #

场景 推荐方案
需要反向映射 数字枚举
需要更好的可读性 字符串枚举
需要最小化代码 const枚举
简单的值集合 联合类型
需要运行时遍历 普通枚举或对象常量

十二、总结 #

本章介绍了TypeScript枚举类型:

枚举类型 #

  1. 数字枚举:默认从0递增,支持反向映射
  2. 字符串枚举:需要显式初始化,不支持反向映射
  3. 异构枚举:混合数字和字符串,不推荐使用
  4. const枚举:编译时内联,性能最优

最佳实践 #

  1. 使用const枚举优化性能
  2. 使用字符串枚举提高可读性
  3. 避免异构枚举
  4. 使用枚举代替魔法数字
  5. 根据场景选择枚举或联合类型
最后更新:2026-03-26