閱讀今天的文章前,先回顧一下昨天的學習,回答看看:
- 複合型別有哪兩種?分別用在哪些情境?
- 什麼是型別檢測(Type Guard)?
如果有點不清楚答案的話,可以看看 Day14 的文章喔!
Never 型別於 TS 2.0 版本提出,表示那些永遠不存在的值的型別,更具體來說像是:
咦,怎麼 never 似乎跟 void 有點像?那兩者的差別是什麼?
補充:never v.s. void 的差異
回傳 void 的函式不會終止函式,也就是說雖然沒有回傳值,但函式會繼續執行; 但是,回傳 never 型別的函式則是應該會回傳,但由於函式中斷執行或者是無限迴圈,因而永遠不會回傳或回傳錯誤的函式。
舉例來說:
let neverEnd = function foever(){ while(true){ //執行程式碼 } } let noReturn = function greet(){ console.log('hello') }
第一個函式 TS 推論結果為 () => never,while無窮迴圈,沒有函式結束的執行點
第二個函式 TS 推論結果為 () => void,不會有回傳值,但函式完整執行
變數也可以註記為 never 型別
let foo: never
但是要注意的是 never 只能賦值給 never。我們來看看 TS 2.0 版本說明 never 型別的原文。
- No type is a subtype of or assignable to never (except never itself).
翻譯一下,整句的意思是指任何型別除了 never 本身以外,皆不是 never 的子型別,換句話說,如果賦值數字、字串等其他型別給 never型別的變數,TS 就會報錯。
let foo: never = 123; // Error: number 型別不能賦值給 never 型別
其實,這個原則不難推敲,回到前面提到函式回傳值為 never ,代表的是執行過程中有錯誤或無法終止,也因此,根本不可能有回傳值,所以也不可能是除了 never 之外的任何型別了。
再來,原始文檔也有提到
- never is a subtype of and assignable to every type.
never 是所有型別的子型別,且可以賦值給所有型別。好像繞口令,這是什麼意思呢?
簡單來說,所有型別中都包含 never。由於 never 通常用在代表函式或方法的回傳值上,想成「任何函式或方法都可能有錯誤」就更好理解了。
來看個範例吧!
function foo(x: string | number): boolean | never {
if (typeof x === 'string') {
return true;
} else if (typeof x === 'number') {
return false;
}
//TS 聰明推斷此為 never 型別
return fail('something failed');
}
function fail(message: string): never {
throw new Error(message);
}
在上面的程式碼中,函式 foo 的參數可以是字串或數字,而回傳值可以是布林值或 never ,在函式中用到昨天提到的型別檢測(Type Guard)來判斷傳入參數的型別,如果是字串就回傳 true ; 如果是數字就回傳 false,這時候 TS 會判斷剩下的必然為 never 型別(數字和字串都處理完了,傳入其他原先沒有設定的型別當然會報錯囉!)
但是,把滑鼠滑到 foo 函式上一看,會發現函式的回傳值型別只剩下 boolean,似乎 boolean 把 never 給吸收了! 怎麼會這樣? never 跑哪裡去了?
這時候,重新看一下「never 是所有型別的子型別」這句話,也就是說,任何型別都涵蓋 never ,因此,never 在聯合型別中總是會被省略。
type example = boolean | never;
事實上等於
type example = boolean
never 型別推論發生在以下情況:
這時候,TS 會自動推論為 Never 型別。但一旦將某個函式回傳值型別註記為 never 型別,則該函式必須不會有任何結束的執行點。
// 明確註記為 never 型別:函式必須不會有任何結束的執行點
function error(message: string): never {
throw new Error(message);
}
// TS 推論回傳值為 Never
function fail() {
return error("Something failed");
}
// 明確註記為 never 型別:函式不會有任何結束的執行點
function infiniteLoop(): never {
while (true) {
}
}
// 若randow < 0.5 函式有終點,報錯
function randomFail(): never{
let random = Math.random()
if(random >0.5){
throw new Error('error')////Error: A function returning 'never' cannot have a reachable end point.
}
}
來個重點整理吧: Never 型別推論 & 型別註記
- never 型別通常用於函式回傳值型別
- 如果函式沒有註記回傳值型別,TS 會根據 return 表達式回傳的型別或是函式是否回傳來進行型別推斷
- 如果函式沒有任何結束的執行點,則 TS 會自動判斷該函式回傳值為 never
- 如果函式積極註記回傳值為 never 型別,則該函式必須不會有任何結束的執行點
今天介紹了特殊型別的 never 型別,never 型別很常使用在處理函式的錯誤情況,接下來會來學習特殊型別 - Any & Unknown,明天見囉!