iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
JavaScript

TypeScript 初學者也能看的學習指南系列 第 19

TypeScript 初學者也能看的學習指南 19 - never 型別

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240926/20149362eS5yG5hdia.png

never 是 TypeScript 中獨有的型別,本篇要來介紹 never 型別及其使用時機

never

The never type represents values which are never observed.
擷取自官方文件

never 直翻中文就是「從來沒有」、「絕不」
never 型別則表示一個函式或參數絕不會有回傳值,經常使用在以下情境上:

  1. 拋出錯誤、異常的函式上
  2. 程式被中斷或程式被困在裡頭(如無窮迴圈)
  3. 聯合型別中「不可達」的情況
  • 拋出錯誤、異常的函式,是不會有回傳值的,這時候可以把函式的回傳值定義為 never
function error(message: string): never {
  throw new Error(message); 
}
  • 無窮迴圈
let a = function infiniteLoop() {
  while (true) {
  }  // 無窮迴圈,永遠不會有回傳值
}
  • 聯合型別中「不可達」的情況:所有可能型別都已經被排除掉的情況
    如範例中的 x: string | number 代表 x 只能是 string 或 number,這兩者外的都會走到 else,此時 x 就會被推斷為 never,表示剩下的情況「永遠不會發生」~
function fn(x: string | number) {
  if (typeof x === "string") {
    // ... 略 ...
  } else if (typeof x === "number") {
    // ... 略 ...
  } else {
    return x; // ✅ x 推斷為 never
  }
}

把上面例子的 else if 移除,最後的 x 則會被推斷為 number

function fn2(x: string | number) {
  if (typeof x === "string") {
    // ... 略 ...
  } else {
    return x; // ✅ x 推斷為 number
  }
}
  • never 結合 Union Types 會發生什麼事?
type AnotherType = never | string | number;

這個聯合型別推斷出來的結果為 string | number, never 在任何聯合型別中都會因視為 empty type,而被忽略

可指派性 (assignability)

https://ithelp.ithome.com.tw/upload/images/20240929/201493624A4674RCy3.png
登愣~這張圖又出場了

橫軸是「目標型別」;縱軸是「來源型別」
藍色勾勾(✓):來源型別可以被指派給目標型別
綠色勾勾(✓):tsconfig.json 中的 strictNullChecks 關閉時才能被指派

  • never 可以被指派(賦值)給任何型別(如 any、unknown、object、void、undefined、null),這是因為 never 沒有任何實際的回傳值,因此兼容了所有型別,也可以說 never 是所有型別中的子型別(subtype)
function throwError(errMsg: string): never {
  throw new Error(errMsg);
}

let exampleString: string = throwError("Error 1");    // ✅ Pass
let exampleNumber: number = throwError("Error 2");    // ✅ Pass
let exampleBoolean: boolean = throwError("Error 3");  // ✅ Pass
  • 沒有任何型別可以指派(賦值)給 never,包括它自己
let strVal = 'hello'; // : string
let neverVal = function infiniteLoop() {    // : never
  while (true) {}
};

let result: never;
result = strVal;     // ❌ Type 'string' is not assignable to type 'never'.
result = neverVal;   // ❌ Type '() => never' is not assignable to type 'never'.

以上這兩個特性都可以解釋為何官方文件給了 never 一個這樣的說明
https://ithelp.ithome.com.tw/upload/images/20240929/20149362ygsQchqE2z.png

The Bottom Type

https://ithelp.ithome.com.tw/upload/images/20240929/20149362vkGXX39vRO.png
圖片改編自此文章

在 TypeScript 中,never 是 The Bottom Type,any, unknown 則是 The Top Type
The Bottom Type 並非是 TypeScript 裡的專有名詞,在此 wiki 給的解釋是

In type theory, the bottom type of a type system is the type that is a subtype of all other types.
The bottom type may therefore be known as the zero, never or empty type.

never 型別為所有型別的 subtype,因為 never 沒有任何實際的回傳值,兼容了所有型別,因此在某些程式語言中被視為 0、never、空集合(empty type / empty set)

總結

鐵人賽大大 Maxwell Alexius 的 這篇文章有給出更多 never 相關的例子,值得一看,不過有些範例的型別推論結果跟我目前在本地測試並不相同,猜測是是版本問題,那篇文章發佈時間距離現在已過 5 年,但 never 的概念、行為仍是不變的

每天的內容有推到 github 上喔

References


上一篇
TypeScript 初學者也能看的學習指南 18 - undefined、null 型別
下一篇
TypeScript 初學者也能看的學習指南 20 - interface 介面
系列文
TypeScript 初學者也能看的學習指南30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言