写 TypeScript,究竟用枚举还是联合类型?

1,427 阅读2分钟

在用 TypeScript 写项目的时候,经常会需要定义一些状态类型,这个时候就会纠结:究竟是用枚举(enum)呢,还是用联合类型(union type)呢? 如果你也有类似的困惑,不妨继续往下看,我先说结论吧:

联合类型比枚举好。

那究竟好在什么地方呢?下面详细解释:

简洁

定义联合类型很简洁,只需要一行代码而已:

type Status = "idle" | "pending" | "resolved" | "rejected";

而定义枚举类型比较复杂,一行绝对搞不定,例如:

enum Status {
  Idle = "idle",
  Pending = "pending",
  Resolved = "resolved",
  Rejected = "rejected"
}

易扩展

扩展联合类型非常容易,例如:

type Status = "idle" | "pending" | "resolved" | "rejected";
type UserStatus = Status | "existed";

而枚举类型是无法继承和扩展的,你只能再定义一个枚举,把那些值重复写一遍:

enum Status {
  Idle = "idle",
  Pending = "pending",
  Resolved = "resolved",
  Rejected = "rejected"
}

enum UserStatus {
  Idle = "idle",
  Pending = "pending",
  Resolved = "resolved",
  Rejected = "rejected",
  Existed = "existed",
}

无副作用

使用联合类型不仅有类型提示:

type Status = "idle" | "pending" | "resolved" | "rejected";
const status: Status = 'idle'

而且编译出来的代码非常简洁:

var status = 'idle';

再看看用枚举类型做同样的事情:

enum Status {
  Idle = "idle",
  Pending = "pending",
  Resolved = "resolved",
  Rejected = "rejected"
}

const status: Status = Status.Idle

编译出来的代码是一大坨,文件体积增加了好几倍:

var Status;
(function (Status) {
    Status["Idle"] = "idle";
    Status["Pending"] = "pending";
    Status["Resolved"] = "resolved";
    Status["Rejected"] = "rejected";
})(Status || (Status = {}));
var status = Status.Idle;

类型安全

联合类型使用起来是非常安全的,例如:

type Status = "idle" | "pending" | "resolved" | "rejected";
const updateStatus = (newStatus: Status) => { 
  console.log(newStatus);
};
updateStatus("idle"); // 只能输入 Status 定义的 4 个字符串,否则报错

而枚举类型是有先天缺陷的,请看:

enum Status {
  Idle = "idle",
  Pending = "pending",
  Resolved = "resolved",
  Rejected = "rejected"
};
const updateStatus = (newStatus: Status) => {
  console.log(newStatus);
};
updateStatus("idle"); // 这里铁定报错,但 idle 明明是一个枚举范围之内的值啊
updateStatus(Status.Idle); // 只有这样写才行

你也许会说,这样没毛病呀,就是必须指定枚举类型的值,但是你看下面的反人类行为:

enum Status {
  Idle = 0,
  Pending = 1,
  Resolved = 2,
  Rejected = 3
};
const updateStatus = (newStatus: Status) => {
  console.log(newStatus); // 打印 20
};
updateStatus(20); // 这里竟然不会报错

好了,本文就介绍到这了,我反正是不再用枚举了。至于屏幕面前的读者,随便你啦!写代码,无非就是图个开心嘛!