枚举_TypeScript笔记7

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

内容简介:枚举,就是按照枚举值的类型,把枚举分为数值枚举,字符串枚举以及异构枚举。此外,还有特殊的联合枚举,以及常量枚举和环境枚举声明了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

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

参考资料


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

查看所有标签

猜你喜欢:

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

细节决定交互设计的成败

细节决定交互设计的成败

张亮 / 2009-3 / 49.00元

《细节决定交互设计的成败》是一本非常实用的有关软件界面的交互设计和可用性设计方面知识的书籍,通过采用一问一答的形式,你将会有针对性地学习到一些能够很快应用在自己软件开发工作中的细节知识和诀窍。例如,如何减轻用户的等待感,如何预防和减少用户的使用错误等。另外,你会发现阅读《细节决定交互设计的成败》时会非常轻松和愉悦;这是由于《细节决定交互设计的成败》写作上的两个特点:第一,采用较多日常生活中的例子来......一起来看看 《细节决定交互设计的成败》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

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

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具