枚举_TypeScript笔记7

栏目: IOS · 发布时间: 6年前

内容简介:枚举,就是按照枚举值的类型,把枚举分为数值枚举,字符串枚举以及异构枚举。此外,还有特殊的联合枚举,以及常量枚举和环境枚举声明了4个方向常量,值分别为

一.简介

枚举,就是 一组具名常量

Enums allow us to define a set of named constants.

按照枚举值的类型,把枚举分为数值枚举,字符串枚举以及异构枚举。此外,还有特殊的联合枚举,以及常量枚举和环境枚举

二.数值枚举

enum Direction {
  Up,     // 0
  Down,   // 1
  Left,   // 2
  Right,  // 3
}

声明了4个方向常量,值分别为 0, 1, 2, 3 。这些值是自动初始化并自增而来的,想要从指定数值开始也很容易:

enum Direction {
  Up = 1, // 1
  Down,   // 2
  Left,   // 3
  Right,  // 4
}

枚举值的这种 自增机制 相当省事,毕竟在大多数场景下我们并不关心具体的枚举值,只要保证唯一,能与其它同类枚举值区分开即可:

function turn(direction: Direction): void {
  switch (direction) {
    case Direction.Up:
      console.log('Turn up now');
      break;
    case Direction.Down:
      console.log('Turn down now');
      break;
    // ...
    default:
      console.log('Turn around here');
  }
}

自增要有一个起始值,称之为initializer,因此,类似这样的场景下枚举值无法完成初始化:

function getStartValue() { 
  return 1;
}

enum E {
  A = getStartValue(),
  // 报错 Enum member must have initializer.
  B,
}

无法在编译时确定自增起始值,就没办法通过自增机制自动填充枚举值。具体的,没被显式初始化的枚举值,要么最先出现,要么出现在在其它数值常量枚举值之后

反向映射

TypeScript里可用通过枚举值取到对应枚举常量名,这种特性称之为反向映射(reverse mapping),例如:

enum Direction {
  Up,
  Down,
  Left,
  Right,
}
// 正向 按名取值
console.log(Direction.Down);  // 1
// 反向 按值取名
console.log(Direction[1]);    // 'Down'

因为在声明数值枚举的同时建立了反向关系:

var Direction;
(function (Direction) {
  Direction[Direction["Up"] = 0] = "Up";
  Direction[Direction["Down"] = 1] = "Down";
  Direction[Direction["Left"] = 2] = "Left";
  Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));

// ["0", "1", "2", "3", "Up", "Down", "Left", "Right"]
console.log(Object.keys(Direction));

仅限于数值枚举 (为了弥补数值枚举在运行时的可读性缺陷),其它类型的枚举并不建立反向关系

三.字符串枚举

enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT",
}

与数值枚举类似,字符串枚举的枚举值都是字符串,但有2点差异:

  • 字符串枚举没有自增机制,要求每个成员都显式初始化

  • 字符串枚举没有反向映射

对比数值枚举,字符串枚举的一大优势是在运行时仍能保留值的含义(比如Debug时取枚举值,仍然是可读的):

String enums allow you to give a meaningful and readable value when your code runs, independent of the name of the enum member itself.

自增而来的失去了可读性,所以不支持自增。同理,字符串枚举值本就可读,不再需要反向映射:

var Direction;
(function (Direction) {
  Direction["Up"] = "UP";
  Direction["Down"] = "DOWN";
  Direction["Left"] = "LEFT";
  Direction["Right"] = "RIGHT";
})(Direction || (Direction = {}));

四.异构枚举

enum mixEnum {
  S = 'S',
  A = 0,
  B,
  C = "C",
}

枚举值中既有数值也有字符串时,称之为异构枚举(heterogeneous enumeration)。此时根据值的类型,按照数值枚举和字符串枚举区别对待,例如:

var mixEnum;
(function (mixEnum) {
  mixEnum["S"] = "S";
  mixEnum[mixEnum["A"] = 0] = "A";
  mixEnum[mixEnum["B"] = 1] = "B";
  mixEnum["C"] = "C";
})(mixEnum || (mixEnum = {}));

P.S.语法上允许存在这样的“混合”枚举,但几乎没有理由这样做

常量值与计算值

枚举值要么是常量(constant),要么是计算值(computed)

具体的,常量是指:

  • 第一个枚举成员,且没有初始值,就隐式赋值为0

  • 没有初始值,且上一个枚举成员是个数值常量,就隐式赋值为上一个枚举值加一

  • 枚举成员被显式赋值为常量枚举表达式(TypeScript表达式的子集,能在编译时求值,具体见 constant enum expression

例如:

enum FileAccess {
  // constant members
  None,
  Read    = 1 << 1,
  Write   = 1 << 2,
  ReadWrite  = Read | Write,
  // computed member
  G = "123".length
}

五.联合枚举

特殊的,常量枚举成员中有一部分不需要在编译时求值:字面量枚举成员。包括那些没有初始值的常量枚举成员,或者被初始化成:

  • 字符串字面量

  • 数值字面量

  • 带负号的数值字面量

如果所有成员都是字面量枚举成员,就叫联合枚举(union enums),此时会解锁一些新的特性:

  • 枚举本身有了确切的类型含义(是所有枚举成员的联合体)

  • 枚举成员也有了类型含义

枚举的类型

把枚举用作类型,可以约束取值集合,进而暴露类似的潜在问题:

// 联合枚举
enum E {
  Foo,
  Bar,
}

// 枚举的类型含义
function f(x: E) {
  // This condition will always return 'true' since the types 'E.Foo' and 'E.Bar' have no overlap.
  if (x !== E.Foo || x !== E.Bar) {
    //...
  }
}

枚举成员的类型

把枚举成员用作类型,可以明确要求只接受该枚举值:

// 联合枚举
enum ShapeKind {
  Circle,
  Square,
}

interface Circle {
  // 枚举成员的类型含义
  kind: ShapeKind.Circle;
  radius: number;
}

interface Square {
  kind: ShapeKind.Square;
  sideLength: number;
}

let c: Circle = {
  // 报错 Type 'ShapeKind.Square' is not assignable to type 'ShapeKind.Circle'.
  kind: ShapeKind.Square,
  radius: 100,
}

六.常量枚举

上面介绍的几种枚举都与Class类似,具有值和类型的双重含义,因此在运行时也存在(不像接口只存在于编译时),例如:

// 编译前
enum Enum {
  A = 1,
  B = A * 2
}
let A = Enum.A;
// 编译后
var Enum;
(function (Enum) {
  Enum[Enum["A"] = 1] = "A";
  Enum[Enum["B"] = 2] = "B";
})(Enum || (Enum = {}));
var A = Enum.A;

常量枚举仅存在于编译时 ,具体的,删掉枚举声明,引用处编译替换成常量,例如:

// 编译前(注意 const 修饰符)
const enum Enum {
  A = 1,
  B = A * 2
}
let A = Enum.A;
// 编译后(Enum完全消失了)
var A = 1 /* A */;

因此常量枚举中不允许存在计算值:

const enum Enum {
  // 报错 const enum member initializers can only contain literal values and other computed enum values.
  A = Math.PI
}

七.环境枚举

仅用作类型约束(或者说只声明不实现)的枚举,这一点与常量枚举类似,但环境枚举(ambient enums)用来描述现有枚举的类型,例如:

declare enum CSSNumericBaseType {
  'length',
  'angle',
  'time',
  'frequency',
  'resolution',
  'flex',
  'percent',
}

(摘自 DefinitelyTyped/types/w3c-css-typed-object-model-level-1/index.d.ts

环境枚举与其它枚举的区别在于,环境枚举中没有初始值的枚举成员都当做计算值,不论上一个枚举成员是不是数值常量

参考资料


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Go Web 编程

Go Web 编程

[新加坡]Sau Sheong Chang(郑兆雄) / 黄健宏 / 人民邮电出版社 / 2017-11-22 / 79

《Go Web 编程》原名《Go Web Programming》,原书由新加坡开发者郑兆雄(Sau Sheong Chang)创作、 Manning 出版社出版,人名邮电出版社引进了该书的中文版权,并将其交由黄健宏进行翻译。 《Go Web 编程》一书围绕一个网络论坛 作为例子,教授读者如何使用请求处理器、多路复用器、模板引擎、存储系统等核心组件去构建一个 Go Web 应用,然后在该应用......一起来看看 《Go Web 编程》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具