剖析Typescript枚举(enum)类型

枚举类型

枚举类型在很多语言中都有,一般用于一组命名的场数,当一个变量会出现几种可能的取值是,可以用到枚举类型;

数字枚举

当我们声明一个枚举时,虽然看上去好像煤油给它赋值,但是他们的值其实就是默认的数字类型,并且默认从0开始依次累加:

enum Direction {
    Up,
    Down,
    Left,
    Right
}

console.log(Direction.Up === 0); // true
console.log(Direction.Down === 1); // true
console.log(Direction.Left === 2); // true
console.log(Direction.Right === 3); // true

因此当我们把第一个值赋值后,后边就会参照第一个值进行累加操作,比如:

/**
 * @description 初始赋值的枚举
 */
enum Direct {
    Up = 10,
    Down,
    Left,
    Right
}
console.log(Direct.Down); // 11
console.log(Direct.Left); //12
console.log(Direct.Right); //13

原理明白了,我们看一下实际编译后,这段ts代码变成怎么想的js代码;

/**
 * @description 初始赋值的枚举
 */
var Direct;
(function (Direct) {
    Direct[Direct["Up"] = 10] = "Up";
    Direct[Direct["Down"] = 11] = "Down";
    Direct[Direct["Left"] = 12] = "Left";
    Direct[Direct["Right"] = 13] = "Right";
})(Direct || (Direct = {}));
console.log(Direct.Down); //11
console.log(Direct.Left); //12
console.log(Direct.Right); //13

字符串枚举

枚举类型可以是数字当然也可以是字符串,下边我们看一下字符串枚举类型:


/**
 * @description 字符串枚举
 */
enum DirectStr {
    Up = 'up',
    Down = 'down',
    Left = 'left',
    Right = 'right'
}

console.log(DirectStr['Up'], DirectStr.Right) // up, right

异构枚举

这种结构是什么意思呢?就是既有字符串枚举又由数字枚举,是不是能混合使用呢?试一下吧;

/**
 * @description 异构枚举
 */
enum StrAndNumberEnum {
    no = 0,
    yes = 'ok'
}
console.log(StrAndNumberEnum.no, StrAndNumberEnum.yes) // 0,yes

运行发现,这样是没有问题的,一般情况我们不会使用这种枚举,但是从技术角度,是可行的;

反向映射

我们想一下既然枚举类型可以正常获取值;但是我们想一下能不通过反向映射获取到对应的键呢?可以试一下。

/**
 * @description 反向映射
 */
enum Reverse {
    Up = 10,
    Down,
    Left,
    Right
}
console.log(Reverse[11]) //Down
console.log(Reverse[12]) //Left
console.log(Reverse[13]) //Right

这是不是很奇怪,为啥子?我们都知道js的对象一般都是键值对的正向映射,即 name -> value,为什么正在枚举正反相同时映射?我们需要了解和思考一下枚举的本质;

枚举的本质

以上边Reverse 枚举类型为例子,我们看一下枚举没醒被编译后会变成什么样

/**
 * @description 反向映射
 */
var Reverse;
(function (Reverse) {
    Reverse[Reverse["Up"] = 10] = "Up";
    Reverse[Reverse["Down"] = 11] = "Down";
    Reverse[Reverse["Left"] = 12] = "Left";
    Reverse[Reverse["Right"] = 13] = "Right";
})(Reverse || (Reverse = {}));
console.log(Reverse[11]); //
console.log(Reverse[12]);
console.log(Reverse[13]);

通过分析代码,我们发现Reverse是通过一个自执行函数,通过参数透传的方式为自定义函数赋值;其中Reverse[Reverse[“Up”]=10] = Up我们可以把它理解成Reverse[10]= “Up”;这个特殊的构造,导致其拥有正反向同时映射的特性;

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

枚举中的所有成员都是字面量类型的值,这种请况,每个枚举成员和枚举值本身都可以作为类型来使用;

  • 任何字符串字面量:
/**
 * @description 任何字符串字面量
 */
const enum EveryStr {
    One = '1',
    Two = '2',
    Three = '3',
    Four = '4'
}
  • 任何数字字面量:
/**
 * @description 任何数字字面量
 */
const enum EveryNum{
    Up,
    Down,
    Left,
    Right
}

枚举成员的类型

每个枚举的成员拥有字面量枚举时,被赋予了一定特殊的语义,发现枚举成员成了类型。
比如我们声明一个数字类型:

enum EveryNum{
    Up,
    Down,
    Left,
    Right
}
const  up = 0;

console.log(up ===EveryNum.Up ); //true

枚举成员作为值来使用,通过代码是ok的,因为EveryNum.Up本身默认值就是0;我们写一个类型来验证一下

type c = 0

declare let b: c

b = 1 // 不能将类型“1”分配给类型“0”
b = Direction.Up 

这里b在赋值的时候会发现报错了;这个就是枚举的成员被赋予特殊的类型;类型与类型之间不可以重新赋值;

联合类型

这个比较复杂,这里简单验证一下;

enum KeyHandler {
    Up,
    Down,
    Left,
    Right
}

declare let keyTest: KeyHandler;
enum Animal {
    Dog,
    Cat
}

keyTest = KeyHandler.Up;
keyTest = Animal.Dog // 不能将类型“Animal.Dog”分配给类型“KeyHandler”

发现 把 testKey声明为KeyHandler类型,可以看成我们声明一个联合类型 KeyHandler .Up | KeyHandler .Down| KeyHandler .Left| KeyHandler .Right,只允许这四种类型成员才符合要求。

枚举合并

我们可以把多次声明的枚举进行自动合并;

/**
 * @description 枚举自动合并
 */
enum Collection {
    Name = "张三",
    Sex = 0,
    Age = "21",
    Address = "四川省成都市高新区"
}

enum Collection {
    nation = "汉族"
}

编译成js后,我们看一下是什么样子

var Collection;
(function (Collection) {
    Collection["Name"] = "\u5F20\u4E09";
    Collection[Collection["Sex"] = 0] = "Sex";
    Collection["Age"] = "21";
    Collection["Address"] = "\u56DB\u5DDD\u7701\u6210\u90FD\u5E02\u9AD8\u65B0\u533A";
})(Collection || (Collection = {}));
(function (Collection) {
    Collection["nation"] = "\u6C49\u65CF";
})(Collection || (Collection = {}));

为枚举增加静态方法

借助于namespace命名空间,我们甚至可以给枚举增加一些静态方法。尝试一下;

enum Month {
    January,
    February,
    March,
    April,
    May,
    June,
    July,
    August,
    September,
    October,
    November,
    December,
}

function isSummer(month: Month) {
    switch (month) {
        case Month.June:
        case Month.July:
        case Month.August:
            return true;
        default:
            return false
    }
}

借助命名空间把枚举和静态方法结合起来;

namespace Month {
    export function isSummer(month: Month) {
        switch (month) {
            case Month.June:
            case Month.July:
            case Month.August:
                return true;
            default:
                return false
        }
    }
}
console.log(Month.isSummer(Month.June)) //true
console.log(Month.isSummer(Month.January)) // false

总结

本次笔记重点探讨了一下枚举的一些形式和特性;欢迎交流

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值