[Day23] TS:谈谈让人又爱又恨的 enum

enum

在 TypeScript 中,enum 算是还蛮常会使用到的型别,但有时如果用的不好或观念不够清楚的话,就会有点痛苦而不知所以然。

以下面这个 GENDER 来说:

enum GENDER {
  MALE = 'male',
  FEMALE = 'female',
}

我们知道使用 GENDER.MALE 可以取得 "male",所以有时侯会直觉的想说,那 "male" 应该算是 GENDER 的子集合吧!?而这也是笔者在使用 enum 时很容易忽略或犯的错误。

让我们来做一点小测验,读者可以想想看,下面这些条件会是 true 或 false:

type T1 = GENDER extends string ? true : false;
type T2 = string extends GENDER ? true : false;

type T3 = number extends GENDER ? true : false;

type T4 = 'male' extends GENDER ? true : false;
type T5 = GENDER.MALE extends GENDER ? true : false;
type T6 = GENDER.MALE extends string ? true : false;

这里的重点是要区分清楚 "male""female"GENDER(enum) 和 string 它们彼此间的关系,如果我们用一张图来表示,会类似像这样:

Screen Shot 2021-10-08 at 11.39.11 PM

特别留意上图中的 GENDER.MALE"male" 的部分。

发现了吗?虽然说我们知道,透过 GENDER.MALE 可以取得 "male",但实际上 "male" 并不是 GENDER 这个 enum 的子集合!更具体来说,从值的角度思考时 GENDER.MALE"male" 是一样的,但从型别的角度思考是 GENDER.MALE"male" 互不是彼此的子集合,这个概念真的蛮重要的。上面提供的程序码,便是用 Conditional Type 的方式来验证这样的关系:

enum STRING_GENDER {
  MALE = 'male',
  FEMALE = 'female',
}

type T1 = STRING_GENDER extends string ? true : false; // true
type T2 = string extends STRING_GENDER ? true : false; // false
type T3 = string extends STRING_GENDER.MALE ? true : false; // false
type T4 = 'male' extends STRING_GENDER ? true : false; // false
type T5 = 'male' extends STRING_GENDER.MALE ? true : false; // false
type T6 = STRING_GENDER.MALE extends STRING_GENDER ? true : false; // true
type T7 = STRING_GENDER.MALE extends string ? true : false; // true
type T8 = STRING_GENDER extends STRING_GENDER.MALE ? true : false; // false

另外,虽然 GENDER.MALE"male" 彼此之间没有从属关系外,但它们都还是属於型别 string 的子集合。

上面这个部分要谢谢同事 Peter 协助笔者厘清与理解。

Numeric enums

上面说明的是 string enums 的情况,也就是 enum 的 value 是 string 时,但另外常用的 enum 还有 numeric enums 这时候在集合的表现上会有所不同,有兴趣的读者可以再自行尝试看:

enum NUMERIC_GENDER {
  MALE,
  FEMALE,
}

type T11 = NUMERIC_GENDER extends number ? true : false; // true
type T12 = number extends NUMERIC_GENDER ? true : false; // true
type T13 = number extends NUMERIC_GENDER.MALE ? true : false; // true
type T14 = 10 extends NUMERIC_GENDER ? true : false; // true
type T15 = 10 extends NUMERIC_GENDER.MALE ? true : false; // true
type T16 = NUMERIC_GENDER.MALE extends NUMERIC_GENDER ? true : false; // true
type T17 = NUMERIC_GENDER.MALE extends number ? true : false; // true
type T18 = NUMERIC_GENDER extends NUMERIC_GENDER.MALE ? true : false; // false
type T19 = NUMERIC_GENDER.MALE extends NUMERIC_GENDER.FEMALE ? true : false; // false

范例程序码

https://tsplay.dev/w11MGw @ TypeScript Playground

参考资料

  • 同事
  • enums @ TypeScript

<<:  [Q&A] 08 补完一个漏洞还有谜个漏洞

>>:  【第23天】部署API服务-GCP架设VM(一)

[day10] Flask Python API Service

安装Flask跟套件 pip install flask pip install flask-res...

day 4 I'm your father, coroutine父子继承关系

上面讲到job会由系统分配,但为什麽我们又能把job当作参数传入coroutine呢? 继承 在前面...

Day 29 整合宝石:【Lab】建构三层式云端架构 (EC2+VPC+S3+RDS+IAM) (上)

(转眼间到最後两天,发现想谈及的主题谈不完,所以最後这两篇整合宝石的文章会特别长~,因为如果照之前...

[Android Studio菜鸟的学习分享]我不是机器人-Google reCAPTCHA

Google reCAPTCHA是Google开发的防堵机器人验证API, 原本是设计给网页使用, ...

从 JavaScript 角度学 Python(8) - BMI 计算(1)

前言 接下来这一篇算是收割前面几个章节的章节小练习,基本上我是尽量规划每过几个章节就有一些小作业、小...