iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 15
2
自我挑戰組

Typescript 初心者手札系列 第 15

【Day 15】TypeScript 資料型別 - 特殊型別(上)- Never

  • 分享至 

  • xImage
  •  

閱讀今天的文章前,先回顧一下昨天的學習,回答看看:

  • 複合型別有哪兩種?分別用在哪些情境?
  • 什麼是型別檢測(Type Guard)?

如果有點不清楚答案的話,可以看看 Day14 的文章喔!

Never 型別於 TS 2.0 版本提出,表示那些永遠不存在的值的型別,更具體來說像是:

  1. 應該要回傳,但卻沒有回傳值的函式(例如:如果函式內有無窮迴圈,沒有任何結束的執行點)
  2. 總是會拋出錯誤的函式

咦,怎麼 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 型別的原文。

  1. 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 之外的任何型別了。

再來,原始文檔也有提到

  1. 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 型別推論 & 註記

never 型別推論發生在以下情況:

  1. 函式沒有回傳值或return 表達式回傳的值之型別為 never
  2. 函式必須不會有任何結束的執行點

這時候,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 型別推論 & 型別註記

  1. never 型別通常用於函式回傳值型別
  2. 如果函式沒有註記回傳值型別,TS 會根據 return 表達式回傳的型別或是函式是否回傳來進行型別推斷
  3. 如果函式沒有任何結束的執行點,則 TS 會自動判斷該函式回傳值為 never
  4. 如果函式積極註記回傳值為 never 型別,則該函式必須不會有任何結束的執行點

小結

今天介紹了特殊型別的 never 型別,never 型別很常使用在處理函式的錯誤情況,接下來會來學習特殊型別 - Any & Unknown,明天見囉!


上一篇
【Day 14】TypeScript 資料型別 - 複合型別(Union & Intersection) & 型別檢測(Type Guard)
下一篇
【Day 16】TypeScript 資料型別 - 特殊型別(下)- Any & Unknown
系列文
Typescript 初心者手札30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言