Typescript 如何用枚举来放飞自我的

阅读本文之前,请投票支持这款 全新设计的脚手架 ,让 Java 再次伟大!

枚举

枚举是对客观事物的归纳与自然语言的抽象。这听起来似乎容易和类混淆,这是正常的。因为在大部分面向对象的语言里,枚举就是类。

我们知道一周有七天 —— Week={monday,Tuesday,...., Sunday}。假设用枚举来描述这个概念的话就是下面这样:

enum Week {
  Monday,
  Tuesday,
  Sunday,
}

你可能会说用常量也可以表示这个概念。但是,常量无法体现「今天只能是一周中的某一天」—— Today ∈ Week={monday,Tuesday,...., Sunday} 这个概念。

enum Week {
  Monday,
  Tuesday,
  Sunday,
}

function f(today: Week) {
  if (today === Week.Monday) {
    console.log("today is Monday!");
  }
}

// f("happyDay");  ==> type error! string is not Enum
f(Week.Monday);

typescript 中枚举的行为

到目前为止,上述示例代码中的枚举行为都是符合预期的。但是「一切正常」向来不是 javascript 的风格。

在 ts 中,下面这样的代码也可以编译成功。

enum Week {
  Monday = "Monday",
  Tuesday = "Tuesday",
  Sunday = 7,
}
console.log(Week);
console.log(Week["Monday"]); // ===> Monday

// f("day");  ==> type error! string is not Enum
function soo(option: string) {
  if (option === Week.Monday) {
    console.log("today is Monday!");
  }
}
soo(Week.Monday);

function doo(option: {}) {
  if (option === Week.Monday) {
    console.log("today is Monday!");
  }
}
doo(Week);

function foo(option: { Monday: Week.Monday }) {
  if (option.Monday === Week.Monday) {
    console.log("today is Monday!");
  }
}
foo(Week);

只要和真正的面向对象语言中枚举的行为相比较,就能发觉 ts 中枚举的类型检查非常的不严谨。

class Scratch {
    public static void main(String[] args) {
        test(Week.Monday);
    }

    public static void test(Week w) {
        System.out.println(w.name);
        System.out.println(w.code);

        if (w.equals(Week.Monday)) {
            System.out.println(Week.Monday);
        } else if (w.equals(Week.Tuesday)) {
            System.out.println(Week.Tuesday);
        }
    }

    enum Week {
        Monday("Monday", 001),
        Tuesday("Tuesday", 002);
        private String name;
        private Integer code;

        Week(String name, Integer code) {
            this.name = name;
            this.code = code;
        }

        @Override
        public String toString() {
            return "Week{" +
                    "name='" + name + '\'' +
                    ", code=" + code +
                    '}';
        }
    }
}

不严谨就算了,ts 中的数字枚举成员还有「反向映射」这样放飞自我的行为。

enum Week {
  Monday = "Monday",
  Tuesday = "Tuesday",
  Sunday = 7,
}
console.log(Week[7]); // ===> Sunday

typescript 中的枚举是什么

打印 ts 中的枚举会输出一个对象。这个对象的属性由枚举成员的 key 与枚举成员的 value 构成。

enum Week {
  Monday = "Monday",
  Tuesday = "Tuesday",
  Sunday = 7,
}
console.log(Week);

-----------
{ '7': 'Sunday', Monday: 'Monday', Tuesday: 'Tuesday', Sunday: 7 }

要注意的是,数字枚举成员除了生成 key/value 形式的正向映射属性以外,还生成 value/key 的反向映射属性 {'7': 'Sunday'};而字符串枚举成员只会生成正向映射的属性。

这些行为,都来源于 ts 将枚举设计为一个 js 对象,再通过立即执行函数和赋值操作符返回等式右边值的特性,创建这个对象的正反映射属性造成的。

var Week;
(function (Week) {
    Week["Monday"] = "Monday";
    Week["Tuesday"] = "Tuesday";
    Week[Week["Sunday"] = 7] = "Sunday";
})(Week || (Week = {}));

既然枚举就是对象,那通过「句点操作符」访问属性就能够获取到枚举成员的 value,于是可以通过 soo 函数的参数类型验证。

function soo(option: string) {
  if (option === Week.Monday) {
    console.log("today is Monday!");
  }
}
soo(Week.Monday);
soo(Week["Tuesday"]);

同时枚举对象还拥有数字枚举成员的反向映射属性,那么实现「反向映射」功能显然是轻而易举。

console.log(Week[7]); // ===> "Sunday"

而那些使用对象作为参数类型的函数,理所应当的可以编译成功。

function doo(option: {}) {
  if (option === Week.Monday) {
    console.log("today is Monday!");
  }
}
doo(Week);

function foo(option: { Monday: Week.Monday; a: "test" }) {
  if (option.Monday === Week.Monday) {
    console.log("today is Monday!");
  }
}
foo(Week);

最后因为枚举就是对象,对象就是函数,函数就是类;所以在 ts 中枚举也是类,是对客观事物的归纳与自然语言的抽象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值