const枚举 ts_TS Enums

本文详细介绍了TypeScript中的枚举,包括数值枚举、字符串枚举、异构枚举、Lookup Object、常量枚举成员与计算枚举成员,以及const枚举的优化效果。const枚举通过内联方式减少代码体积,但不支持反向映射。declare enum用于声明全局存在的枚举,而declare const enum则在编译时进行值替换。
摘要由CSDN通过智能技术生成

枚举不仅仅是对JS的类型扩展,而且是TS中少有的新特性

数值枚举 vs. 字符串枚举

enum Gender {

Female,

Male

}

枚举成员后面没有任何值的时候,这个枚举就是一个数值枚举,top默认会被初始化为0,后面的成员的值依次自增。

当然也可以显示的给枚举成员初始化值

enum Gender {

Female = 1,

Male

}

同样的,后面的成员值会依次递增。

字符串枚举中的每一个成员都要有一个初始值,这个初始值可以是一个字面量,也可以是别的字符串枚举里成员的值。

enum Gender {

Female = 'female',

Male

}

// ts 编译器会提示 Male 必须有个初始值。

字符串枚举并不存在像数值枚举那样的自增行为。字符串枚举的好处是,成员值可以通过字符串携带信息,不像数值枚举一样是难以记忆的数字(实际上反向映射可以做到拿到成员的名字,不过麻烦一点),让程序可读性更高。

异构枚举

如果一个枚举的成员值既有数值也有字符串,那么它就是一个异构枚举。

enum Gender {

Female = 'female',

Male = 0,

others

}

// others 是1

enum Gender {

others

Female = 'female',

Male = 1

}

// others 是 0

enum Gender {

Female = 'female',

others

Male = 0

}

// 编译器提示others得有初始值

Lookup Object

当用enum关键字定义常规的枚举值的时候(注意enum关键字前面既没有const,也没有declare)

enum Gender {

Female,

Male

}

会被ts compiler编译成

"use strict";

var Gender;

(function (Gender) {

Gender[Gender["Female"] = 0] = "Female";

Gender[Gender["Male"] = 1] = "Male";

})(Gender || (Gender = {}));

可以看到Gender编译时实际上被转换成一个有4个键值对的对象,我们把它称作Lookup Object。这个对象既可以按照枚举值中的成员名字查找对应的值,比如Gender.Female会得到0;也可以反向映射(Reverse Mapping),用成员的值查出对应的成员名字,比如Gender[0]会得到"female"。

注:只有数值枚举成员会的转换会有反向映射,字符串枚举成员并不会。

常量枚举成员和计算枚举成员

计算枚举成员的值在编译阶段是不可知的,通常在运行的时候才可以知道,而常量枚举成员的值编译阶段是已经确定的。

常量枚举成员的情形如果枚举的第一个成员没有初始值,默认会被赋值0

枚举成员没有初始值,但是它前面的一个成员值是数值常量

常量枚举表达式(就是编译时完全可以计算结果的表达式)。

常量枚举表达式的情形数值或字符串自变量

引用定义好的常量枚举成员

带括号的常量枚举表达式

带一元操作符的常量枚举表达式(+,-,~)

带二元操作符的常量枚举表达式(+,-,*,/,%,<>,>>>,&,|,^)

除上面列举情形下的是常量枚举成员,其他的都是计算枚举成员。

const和non-const枚举

如果我们在代码中大量使用普通的枚举,最终生成的代码无疑会变多,因为枚举会转换成真实的对象代码。比如下面的转换过程

enum Gender {

Female,

Male

}

console.log(Gender.Female)

//-------- tsc生成的代码 -----

"use strict";

// let a = [1, 2,3]var Gender;

(function (Gender) {

Gender[Gender["Female"] = 0] = "Female";

// others, Gender[Gender["Male"] = 1] = "Male";

})(Gender || (Gender = {}));

console.log(Gender.Female);

我们只是想打印个Female的值0而已,tsc令人窒息的生成了一堆代码。有没有办法不要上面生成lookup object的一坨代码,直接编译成console.log(0)呢。

我们知道ts代码是静态编译的,我们如果想只生成console.log(0),那么Gender.Female的值在编译时应该是确定的才行。回顾之前的内容,会知道常量枚举成员在编译阶段的值是已知的,我们可以利用这一点达到目的。

好在TypeScript可以用const来实现!它的方式就是利用常量枚举成员的特性,在编译阶段做值替换,减少最终生成代码的体积。TS官方文档把这种替换叫做内联(inline)。

在TS的playground里看一下上面的代码使用const enum是什么样的

"use strict";

console.log(0 /* Female */);

十分完美的实现了我们想要的效果,没有对象生成,仅仅替换了值。

我们根据上面的描述,可以推断出const enum的一些特点首先const enum的成员必须是常量枚举成员(编译时值不确定无法做内联[即替换])

const enum没有办法做反向映射(因为没有对象生成嘛)

没有办法使用定义的枚举”对象“ (比如console.log(Gender), 根本就不存在这个对象值,因为没有对象生成),只能使用枚举成员。

通过内联的方式,生成的代码比起常规的枚举要简洁许多,优化了代码。

declare enum 和 declare const enum

declare的作用是告诉ts编译器一些外部的上下文(ambient context),具体的可以查看一下官方文档。类似const enum,它在编译时是没有js代码生成的。一个常见的例子就是jQuery中的$符号,它是一个全局的变量,但是编译器是不知道的,必须告诉编译器存在一个这样的全局变量,我可以在项目的任何地方都使用。对于declare enum,也是同样的意思,编译器通过这个声明会知道,有个提前定义好的Gender可以在全局环境下使用。

declare enum Gender {

Female,

Male

}

console.log(Gender.Female)

//-------- tsc生成的代码 -----

"use strict";

console.log(Gender.Female);

编译时并不会报错,需要注意的是,如果并不存在一个全局可用的Gender,console.log这一句在执行的时候会报错。

为什么呢?道理很简单,因为你欺骗了编译器,告诉它存在一个实际不存在的全局变量。

然而有些时候,我们又想在全局,像之前的const enum中提到的一样,开启inline的功能,这时候就要用到declare const enum。

declare const enum Gender {

Female,

Male

}

console.log(Gender.Female)

//-------- tsc生成的代码 -----

"use strict";

console.log(0 /* Female */);

它不会介意你全局有没有一个实际的Gender,而是仅仅在编译做了值的替换。再回忆下,什么样的枚举成员编译时才能inline?当然是常量枚举成员。

枚举作为类型

枚举成员作为类型

当枚举成员值为字面量时,枚举成员本身就可以作为类型来使用。TSC检测到类型不匹配

枚举作为类型

枚举本身作为类型的时候, 有点像联合类型(union type), 即TSC知道foo是来自Gender枚举成员的候选集。

Enums · TypeScript​www.typescriptlang.orghttps://stackoverflow.com/questions/40227401/const-enum-in-typescript​stackoverflow.comhttps://stackoverflow.com/questions/28818849/how-do-the-different-enum-variants-work-in-typescript​stackoverflow.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值