枚举类型
我们也可以使用 enum 关键字定义枚举类型,格式是 enum + 枚举名字 + 一对花括弧,花括弧里则是被命名了的常量成员。
下面我们把表示星期的联合类型示例使用枚举类型实现一遍,如下代码所示:
enum Day {SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY}
JavaScript 中其实并没有与枚举类型对应的原始实现,而 TypeScript 转译器会把枚举类型转译为一个属性为常量、命名值从 0 开始递增数字映射的对象,在功能层面达到与枚举一致的效果(然而不是所有的特性在 JavaScript 中都有对应的实现)。
下面我们通过如下所示示例看看将如上示例转译为 JavaScript 后的效果。
var Day = void 0;(function (Day) {Day[Day["SUNDAY"] = 0] = "SUNDAY";Day[Day["MONDAY"] = 1] = "MONDAY";Day[Day["TUESDAY"] = 2] = "TUESDAY";Day[Day["WEDNESDAY"] = 3] = "WEDNESDAY";Day[Day["THURSDAY"] = 4] = "THURSDAY";Day[Day["FRIDAY"] = 5] = "FRIDAY";Day[Day["SATURDAY"] = 6] = "SATURDAY";})(Day || (Day = {}));
在 TypeScript 中,我们可以通过“枚举名字.常量命名”的格式获取枚举集合里的成员,如下代码所示:
function work(d: Day) {switch (d) {case Day.SUNDAY:case Day.SATURDAY:return 'take a rest';case Day.MONDAY:case Day.TUESDAY:case Day.WEDNESDAY:case Day.THURSDAY:case Day.FRIDAY:return 'work hard';}}
数字枚举
从上边示例可知,在仅仅指定常量命名的情况下,我们定义的就是一个默认从 0 开始递增的数字集合,称之为数字枚举。
如果我们希望枚举值从其他值开始递增,则可以通过“常量命名 = 数值” 的格式显示指定枚举成员的初始值,如下代码所示:
enum Day {SUNDAY = 1,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY}
事实上,我们可以给 SUNDAY 指定任意类型(比如整数、负数、小数等)、任意起始的数字,其后未显示指定值的成员会递增加 1。
字符串枚举
enum Day {SUNDAY = 'SUNDAY',MONDAY = 'MONDAY',...}
而上述示例转译为 JavaScript 后,Day.SUNDAY 的值依旧是 ‘SUNDAY’,Day.MONDAY 的值依旧是 ‘MONDAY’
相比于没有明确意义的递增值的数字枚举,字符串枚举的成员在运行和调试阶段,更具备明确的含义和可读性,枚举成员的值就是我们显式指定的字符串字面量。
异构枚举(Heterogeneous enums)
从技术上来讲,TypeScript 支持枚举类型同时拥有数字和字符类型的成员,这样的枚举被称之为异构枚举。
enum Day {SUNDAY = 'SUNDAY',MONDAY = 2,...}
常量成员和计算(值)成员
enum FileAccess {// 常量成员None,Read = 1 << 1,Write = 1 << 2,ReadWrite = Read | Write,// 计算成员G = "123".length,}
注意:关于常量成员和计算成员的划分其实比较难理解,实际上它们也并没有太大的用处,只是告诉我们通过这些途径可以定义枚举成员的值。因此,我们只需记住缺省值(从 0 递增)、数字字面量、字符串字面量肯定是常量成员就够了。
常量枚举(const enums)
枚举的作用在于定义被命名的常量集合,而 TypeScript 提供了一些途径让枚举更加易用,比如常量枚举。
const enum Day {SUNDAY,MONDAY}const work = (d: Day) => {switch (d) {case Day.SUNDAY:return 'take a rest';case Day.MONDAY:return 'work hard';}}}
外部枚举(Ambient enums)
在 TypeScript 中,我们可以通过 declare 描述一个在其他地方已经定义过的变量,如下代码所示:
declare let $: any;$('#id').addClass('show'); // ok
同样,我们也可以使用 declare 描述一个在其他地方已经定义过的枚举类型,通过这种方式定义出来的枚举类型,被称之为外部枚举,如下代码所示:
declare enum Day {SUNDAY,MONDAY,}const work = (x: Day) => {if (x === Day.SUNDAY) {x; // 类型是 Day}}
外部枚举和常规枚举的差异在于以下几点:
- 在外部枚举中,如果没有指定初始值的成员都被当作计算(值)成员,这跟常规枚举恰好相反;
- 即便外部枚举只包含字面量成员,这些成员的类型也不会是字面量成员类型,自然完全不具备字面量类型的各种特性。
以上就是“鸡肋”枚举的全部内容,下面我们提炼一下核心的几个知识点和建议:
- 使用常量枚举管理相关的常量,能提高代码的可读性和易维护性;
- 不要使用其他任何类型替换所使用的枚举成员;
