枚举类型是很多语言都拥有的类型,用于声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型。
数字枚举
当声明一个枚举类型时,不给其赋值。此时它们的值是默认的数字类型,而且默认从0开始依次累加。
enum D {a,b,c,d}console.log(D.a === 0) // trueconsole.log(D.b === 1)// trueconsole.log(D.c === 2) // trueconsole.log(D.d === 3) // true
而当把第一个值赋值以后,后面的也会根据第一个值进行累加:
enum D {a = 10,b,c,d}console.log(D.a,D.b,D.c,D.d); // 10,11,12,13
字符串枚举
枚举类型的值可谓字符串类型
enum D {a = 'up',b = 'down',c = 'left',d = 'right'}console.log(D[d],D.a); // right up
异构枚举
混用字符串和数字枚举,从技术角度是可行的。
enum booleanEnum {No = 0,Yes = 'yes'}
反向映射
由以上可知,当我们获取枚举值的时候可通过枚举名字来获取。反向映射是指,通过枚举值来反向获取枚举的名字。(javascript中对象一般都是正向映射的,即name => value,而在枚举中可以正反同时映射,即name <=> value,想要理解这种正反同时映射的特性,需了解下节枚举的本质)
enum D {a,b,c,d}console.log(D[0]); // a
枚举的本质
枚举类型被编译为JavaScript后的样子如下:
var D;(function (D) {D[D['a'] = 10] = 'up';D[D['b'] = 11] = 'down';D[D['c'] = 12] = 'left';D[D['d'] = 13] = 'right';})(D || D = {})
编译后的代码坑看起来比较复杂,不过可以把D看成一个对象。
enum D {a = 10,b,c,d}console.log(D[10],D[d]);// a 13
原因在编译后的JavaScript中体现出来了,因为D[D[‘a’]=10] = ‘a’,即D[10] = ‘a’;所以我们可以把类型看做是一个JavaScript对象,而由于其特殊的构造,导致其拥有正反向同时映射的特性。
常量枚举
枚举可以被const 声明为常量。
const enum D {a = 'a',b = 'b',c = 'c',d = 'd'}const a = D.a;
猜猜被编译为JavaScript后是怎么样的?
var a = "a"
在上面看到枚举类型会被编译为JavaScript对象,而这里没有了。
这就是常量枚举的作用,因为下面的变量a已经使用过了枚举类型,之后就没用了,故没有必要存在于JavaScript中,typescript在这一步就把D去掉了,直接使用D的值即可,这是性能提升的一个方案!
如果非要typescript保留对象D,那么可以添加编译选项 —preserveConstEnums
联合枚举与枚举成员的类型
假设枚举的所有成员都是字面量类型的值,那么枚举的每个成员和枚举值本身都可以作为类型来使用。
任何字符串字面量
const enum D {a = 'a',b = 'b'}
任何数字字面量
enum D {a,b}
应用了一元
-符号的数字字面量enum D {a = -1,b = -2}
枚举成员类型
当所有枚举成员都拥有字面量枚举值时,它就带有了一种特殊的语义,即枚举成员成为了类型。
比如声明一个数字类型:enum D {a,b,c,d}const a = 0;console.log(a === D.a) // true
把成员当做值使用,是没有问题的,因为成员值本身就是0,那么,再加几行代码:
type c = 0declare let b: cb = 1 // 不能将类型“1”分配给类型“0”b = D.a // ok
由此可见,枚举的成员可以被当做类型使用,这就是枚举成员当做类型使用的情况。
联合枚举类型
由于联合联合枚举,类型系统key知道枚举里的值的集合。
enum D{a,b,c,d}declare let a:Denum Animal {Dog,Cat}a = D.a // oka = Animal.Dog // 不能将类型Animal.dog 分配给类型“D”
我们把a 声明为D类型,可以看成我没声明了一个联合类型D.a | D.b | D.c | D.d,只有这四个类型其中的成员才符合要求。
枚举合并
我们可以分开声明枚举,它们会自动合并 ```typescript enum D { a = ‘a’, b = ‘b’, c = ‘c’, d = ‘d’ }
enum D { center = 1 }
编译为JavaScript代码如下:```javascriptvar D;(function()D {D['a'] = 'a';D['b'] = 'b';D['c'] = 'c';D['d'] = 'd';})(D || D = {});(function (D){D[D['center'] = 1] = 'center';})(D || D = {})
为枚举添加静态方法
借助namespace命名空间,我们可以给枚举添加静态方法。
举个栗子:假设有十二个月份:
enum month {Jan,Feb,Marth,April,May,June,July,August,September,October,November,December}
要编写一个静态方法,找出夏天:
function isSummber(month:month) {switch(month){case month.June:case month.July:case month.August:return true;default: return false}}
想要把两者结合,就需要借助命名空间的力量:
namespace month {export function isSummber(month:month) {switch(month) {case month.june:case month.july:case month.august:return true;default: return false}}}console.log(month.issummer(month.january));//false
