枚举类型

我们也可以使用 enum 关键字定义枚举类型,格式是 enum + 枚举名字 + 一对花括弧,花括弧里则是被命名了的常量成员。

下面我们把表示星期的联合类型示例使用枚举类型实现一遍,如下代码所示:

  1. enum Day {
  2. SUNDAY,
  3. MONDAY,
  4. TUESDAY,
  5. WEDNESDAY,
  6. THURSDAY,
  7. FRIDAY,
  8. SATURDAY
  9. }

JavaScript 中其实并没有与枚举类型对应的原始实现,而 TypeScript 转译器会把枚举类型转译为一个属性为常量、命名值从 0 开始递增数字映射的对象,在功能层面达到与枚举一致的效果(然而不是所有的特性在 JavaScript 中都有对应的实现)。
下面我们通过如下所示示例看看将如上示例转译为 JavaScript 后的效果。

  1. var Day = void 0;
  2. (function (Day) {
  3. Day[Day["SUNDAY"] = 0] = "SUNDAY";
  4. Day[Day["MONDAY"] = 1] = "MONDAY";
  5. Day[Day["TUESDAY"] = 2] = "TUESDAY";
  6. Day[Day["WEDNESDAY"] = 3] = "WEDNESDAY";
  7. Day[Day["THURSDAY"] = 4] = "THURSDAY";
  8. Day[Day["FRIDAY"] = 5] = "FRIDAY";
  9. Day[Day["SATURDAY"] = 6] = "SATURDAY";
  10. })(Day || (Day = {}));

在 TypeScript 中,我们可以通过“枚举名字.常量命名”的格式获取枚举集合里的成员,如下代码所示:

  1. function work(d: Day) {
  2. switch (d) {
  3. case Day.SUNDAY:
  4. case Day.SATURDAY:
  5. return 'take a rest';
  6. case Day.MONDAY:
  7. case Day.TUESDAY:
  8. case Day.WEDNESDAY:
  9. case Day.THURSDAY:
  10. case Day.FRIDAY:
  11. return 'work hard';
  12. }
  13. }

数字枚举

从上边示例可知,在仅仅指定常量命名的情况下,我们定义的就是一个默认从 0 开始递增的数字集合,称之为数字枚举。
如果我们希望枚举值从其他值开始递增,则可以通过“常量命名 = 数值” 的格式显示指定枚举成员的初始值,如下代码所示:

  1. enum Day {
  2. SUNDAY = 1,
  3. MONDAY,
  4. TUESDAY,
  5. WEDNESDAY,
  6. THURSDAY,
  7. FRIDAY,
  8. SATURDAY
  9. }

事实上,我们可以给 SUNDAY 指定任意类型(比如整数、负数、小数等)、任意起始的数字,其后未显示指定值的成员会递增加 1。

字符串枚举

  1. enum Day {
  2. SUNDAY = 'SUNDAY',
  3. MONDAY = 'MONDAY',
  4. ...
  5. }

而上述示例转译为 JavaScript 后,Day.SUNDAY 的值依旧是 ‘SUNDAY’,Day.MONDAY 的值依旧是 ‘MONDAY’

相比于没有明确意义的递增值的数字枚举,字符串枚举的成员在运行和调试阶段,更具备明确的含义和可读性,枚举成员的值就是我们显式指定的字符串字面量。

异构枚举(Heterogeneous enums)

从技术上来讲,TypeScript 支持枚举类型同时拥有数字和字符类型的成员,这样的枚举被称之为异构枚举。

  1. enum Day {
  2. SUNDAY = 'SUNDAY',
  3. MONDAY = 2,
  4. ...
  5. }

常量成员和计算(值)成员

  1. enum FileAccess {
  2. // 常量成员
  3. None,
  4. Read = 1 << 1,
  5. Write = 1 << 2,
  6. ReadWrite = Read | Write,
  7. // 计算成员
  8. G = "123".length,
  9. }

注意:关于常量成员和计算成员的划分其实比较难理解,实际上它们也并没有太大的用处,只是告诉我们通过这些途径可以定义枚举成员的值。因此,我们只需记住缺省值(从 0 递增)、数字字面量、字符串字面量肯定是常量成员就够了。

常量枚举(const enums)

枚举的作用在于定义被命名的常量集合,而 TypeScript 提供了一些途径让枚举更加易用,比如常量枚举。

  1. const enum Day {
  2. SUNDAY,
  3. MONDAY
  4. }
  5. const work = (d: Day) => {
  6. switch (d) {
  7. case Day.SUNDAY:
  8. return 'take a rest';
  9. case Day.MONDAY:
  10. return 'work hard';
  11. }
  12. }
  13. }

外部枚举(Ambient enums)

在 TypeScript 中,我们可以通过 declare 描述一个在其他地方已经定义过的变量,如下代码所示:

  1. declare let $: any;
  2. $('#id').addClass('show'); // ok

同样,我们也可以使用 declare 描述一个在其他地方已经定义过的枚举类型,通过这种方式定义出来的枚举类型,被称之为外部枚举,如下代码所示:

  1. declare enum Day {
  2. SUNDAY,
  3. MONDAY,
  4. }
  5. const work = (x: Day) => {
  6. if (x === Day.SUNDAY) {
  7. x; // 类型是 Day
  8. }
  9. }

外部枚举和常规枚举的差异在于以下几点:

  • 在外部枚举中,如果没有指定初始值的成员都被当作计算(值)成员,这跟常规枚举恰好相反;
  • 即便外部枚举只包含字面量成员,这些成员的类型也不会是字面量成员类型,自然完全不具备字面量类型的各种特性。

以上就是“鸡肋”枚举的全部内容,下面我们提炼一下核心的几个知识点和建议:

  1. 使用常量枚举管理相关的常量,能提高代码的可读性和易维护性;
  2. 不要使用其他任何类型替换所使用的枚举成员;