TypeScript(七)枚举

基础类型中简单介绍过枚举,用于将取值限定在一定范围内或定义一些不具有语义性的常量,使之可以清晰的表达意图。

数字枚举

enum Colors {
  red,
  pink,
  blue
}

编译结果:

var Colors
;(function (Colors) {
  Colors[(Colors['red'] = 0)] = 'red'
  Colors[(Colors['pink'] = 1)] = 'pink'
  Colors[(Colors['blue'] = 2)] = 'blue'
})(Colors || (Colors = {}))

枚举成员的值默认从 0 开始自增,同时也会对枚举值到枚举名反向映射。

字符串枚举

在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。不可以使用常量枚举或计算值。

enum Colors {
  red = 'RED',
  pink = 'PINK',
  blue = red
}
Colors.blue // 'RED'

编译结果:

var Colors
;(function (Colors) {
  Colors['red'] = 'RED'
  Colors['pink'] = 'PINK'
  Colors['blue'] = 'RED'
})(Colors || (Colors = {}))

由于字符串枚举没有自增行为,所以字符串枚举可以很好的序列化。 换句话说,数字枚举的值通常并不能表达有用的信息(尽管反向映射会有所帮助),但字符串枚举允许提供一个运行时有意义的并且可读的值,独立于枚举成员的名字。

手动赋值

可以对单个或者全部枚举成员手动赋值。

当对某个枚举成员赋值后,该枚举之后未手动赋值的枚举项会接着递增。

enum Colors {
  red,
  pink = 3,
  blue
}
Colors.blue // 4
enum Colors {
  red = 1,
  pink = 3,
  blue = 5
}
Colors.blue // 5

如果未手动赋值的枚举项与手动赋值的重复了,TypeScript 编译时不会进行限制:

enum Colors {
  red = 3,
  pink = 1,
  blue,
  black,
  orange
}

Colors.red // 3
Colors.black // 3
Colors[3] // 'black'
Colors[3] // 'black'

以上枚举递增到 3 的时候与前面的 red 的取值重复了,但是 TypeScript 并没有报错,导致 Colors[3] 的值先是 "red",而后又被 "black" 覆盖。编译的结果是如下,所以使用的时候需要注意,不要出现覆盖的情况。

var Colors
;(function (Colors) {
  Colors[(Colors['red'] = 3)] = 'red'
  Colors[(Colors['pink'] = 1)] = 'pink'
  Colors[(Colors['blue'] = 2)] = 'blue'
  Colors[(Colors['black'] = 3)] = 'black'
  Colors[(Colors['orange'] = 4)] = 'orange'
})(Colors || (Colors = {}))

此外手动赋值的枚举项也可以为小数或负数,之后未手动赋值的项的递增步长仍为 1:

enum Colors {
  red = 1.5,
  pink,
  blue,
  black = -1,
  orange
}

Colors.pink // 2.5
Colors.orange // 0

常数项和可计算成员

当给某一个枚举成员设置常量或计算所得值后,其之后的成员必须手动初始化。

可计算成员的意思就是:初始化枚举成员时,可使用表达式、函数等方式动态求值,还可以是对之前定义的常量枚举成员的引用。

常数项

const num = 2

enum Colors {
  pink = 4,
  red = num,
  blue = 7
}

以上将常量 num 赋值给枚举成员 red,则其之后的成员必须初始化,否则编译报错:

const num = 2

enum Colors {
  pink = 4,
  red = num,
  blue
}
// Enum member must have initializer.

计算所得值

function getNum() {
  return 3
}
enum Colors {
  red = 1,
  blue = getNum(),
  pink = 6
}
enum Colors {
  red = 1,
  blue = 'sina'.length,
  pink = 6
}

反向映射

除了创建一个以属性名做为对象成员的对象之外,数字枚举的成员还具有反向映射,从枚举值到枚举名。如下:

enum Colors {
  red
}
Colors.red // 0
Colors[0] // 'red'

编译结果:

var Colors
;(function (Colors) {
  Colors[(Colors['red'] = 0)] = 'red'
})(Colors || (Colors = {}))

ts 编译生成的 js 代码中,数字枚举类型被编译成一个对象,包含正向映射( key -> value)和反向映射( value -> key)。

注意:字符串枚举的成员不会生成反向映射。

异构枚举

枚举可以混合字符串和数字成员(不建议)

enum Colors {
  red = 'RED',
  pink = 'PINK',
  blue = 4
}

运行时枚举

枚举在运行时是真正存在的对象,因为 ts 会将枚举编译成 js 对象。

enum Colors {
  red
}

function bar(obj, key) {
  return obj[key]
}
bar(Colors, 'red')

编译结果:

var Colors
;(function (Colors) {
  Colors[(Colors['red'] = 0)] = 'red'
})(Colors || (Colors = {}))

function bar(obj, key) {
  return obj[key]
}
bar(Colors, 'red')

const(常量)枚举

常量枚举通过在枚举上使用 const 修饰符来定义。

const enum Colors {
  red = 4
}
function bar() {
  return Colors.red
}
bar() // 4

常量枚举与普通枚举不一样它会在编译阶段被删除。因为普通枚举会被编译成 js 对象,可以将常量枚举理解成在编译阶段首先生成 js 对象,然后将所有的枚举值计算出来,然后删除对象。

编译结果:

function bar() {
  return 4 /* red */
}
bar()

所以在运行时不可以使用常量枚举。比如:

const enum Colors {
  red
}
console.log(Colors)
// 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query.
//  ("const" 枚举仅可在属性、索引访问表达式、导入声明的右侧、导出分配或类型查询中使用。)

联合枚举与枚举成员的类型

首先解释字面量枚举成员。

字面量枚举成员是指不带有初始值的常量枚举成员,或者是值被初始化为以下三种情况的枚举成员。

  • 任何字符串字面量;
  • 任何数字字面量
  • 应用了一元 - 符号的数字字面量
  1. 不带有初始值的常量枚举成员
enum Colors {
  red
}
  1. 任何字符串字面量:
enum Colors {
  red = 'RED'
}
  1. 任何数字字面量:
enum Colors {
  red = 1
}
  1. 应用了一元 - 符号的数字字面量:
enum Colors {
  red = -10
}

当所有枚举成员都拥有字面量枚举值时,枚举成员或枚举可以当作类型使用。

枚举成员类型

枚举成员类型是指将枚举的某些成员当作类型使用。

enum Colors {
  red = 'RED'
  pink = 'PINK'
}
interface Tomato {
  color: Colors.red
}
const tomato: Tomato = {
  color: Colors.red
  // color: Colors.pink
  // Type 'Colors.pink' is not assignable to type 'Colors.red'.
}

枚举类型

枚举类型本身变成了每个枚举成员的联合类型。

enum Colors {
  red = 'RED',
  pink = 'PINK'
}
interface IColor {
  color: Colors
}

const tomato: IColor = {
  color: Colors.red
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容