iT邦幫忙

2021 iThome 鐵人賽

DAY 23
0
Modern Web

React 前端工程師的兩把刷子系列 第 23

[Day23] TS:談談讓人又愛又恨的 enum

  • 分享至 

  • xImage
  •  

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

上一篇
[Day22] React x TS 中的 Event Handler
下一篇
[Day24] 談談寫測試的好處:從為你自己寫測試開始
系列文
React 前端工程師的兩把刷子30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
TD
iT邦新手 4 級 ‧ 2021-11-06 11:07:49

參考資料裡面的「同事」是?XD

pjchender iT邦新手 3 級 ‧ 2021-11-07 18:12:32 檢舉

哈哈,是同事提供這個知識點的

0
ShawnGood
iT邦新手 4 級 ‧ 2022-03-19 13:03:32

它們的圈圈真的好亂
這圖要怎麼畫呢?

enum NUMERIC_GENDER {
  MALE,
  FEMALE,
}
type one = 0

// 可以很確定 one 和 number 不是同一種type!
// one 是 number 的子集
type T1 = one extends number ? true : false // true
type T2 = number extends one ? true : false // false

// 可以說 NUMERIC_GENDER.MALE 就是 one 嗎?
type T3 = one extends NUMERIC_GENDER.MALE ? true : false // true
type T4 = NUMERIC_GENDER.MALE extends one ? true : false // true

// 唉但是?
type T5 = NUMERIC_GENDER.MALE extends number ? true : false // true
type T6 = number extends NUMERIC_GENDER.MALE ? true : false // true

我要留言

立即登入留言