TypeScript中never類型的妙用詳解
TypeScript 是一種靜態(tài)類型的編程語言,它可以讓我們在編寫 JavaScript 代碼時,提前發(fā)現(xiàn)并避免一些潛在的錯誤。
但是,有時候我們在修改類型時,可能會忘記修改一些相關的代碼,導致類型不匹配或者缺少分支處理等問題。
有沒有一種方法,可以讓我們在修改類型時更加輕松和精確呢?
答案是肯定的!
我是渡一子辰老師,今天我來向你介紹一個重要的類型——never 類型。
它是 TypeScript 中最小的類型,它表示一個永遠不會出現(xiàn)的值。
子辰還將告訴你如何利用 never 類型來確保類型約束的精確性,避免在類型修改過程中導致的錯誤。
什么是 never 類型
在 TypeScript 中,never 類型表示一個永遠不會出現(xiàn)的值。
它是所有類型的子類型,也就是說,任何類型都可以賦值給 never 類型,但是 never 類型不能賦值給任何類型,當然除了它自己。
never 類型有什么用呢?我們可以用它來表示一些永遠不會發(fā)生的情況,比如:
- 拋出異常的函數(shù)
- 死循環(huán)的函數(shù)
- 永遠不會進入的分支
例如:
// 拋出異常的函數(shù) function error(message: string): never { throw new Error(message); } // 死循環(huán)的函數(shù) function loop(): never { while (true) {} } // 永遠不會進入的分支 function foo(x: string | number) { if (typeof x === "string") { // do something } else if (typeof x === "number") { // do something else } else { // x is never const n: never = x; } }
在上面的例子中,error 函數(shù)和 loop 函數(shù)都永遠不會返回任何值,所以它們的返回類型是 never 。
foo 函數(shù)中,如果 x 是 string 或者 number ,就會進入相應的分支處理;如果 x 不是這兩種類型,就會進入最后一個分支,但是這個分支永遠不會進入,因為 x 的類型已經被收縮為 never 了。
所以我們可以用 never 類型來標記這個分支,并且把 x 賦值給一個 never 類型的變量 n ,這樣就可以確保這個分支永遠不會被執(zhí)行。
never 的妙用
我們已經知道了 never 類型可以表示一些永遠不會發(fā)生的情況,那么我們如何利用它來確保類型約束的精確性呢?
我們來看一個例子。
假設我們要封裝一個 Ajax 請求的方法。
// 定義一個類型 type Method = 'GET' | 'POST' // 封裝一個 Ajax 請求的方法,為兩個參數(shù)約束類型 function request(method: Method, url: string) { }
可以看到方法已經寫好了,并且在調用 request 時也有提示了。
那么我們再來寫函數(shù)里邊的東西。
type Method = 'GET' | 'POST' function request(method: Method, url: string) { // 因為有多種請求類型,我們這里用 switch // 每一個類型隨便給它返回一個值僅做模擬 switch (method) { case "GET": return "get" case "POST": return "post" default: return 'default' } }
可以看到函數(shù)里邊用 switch 來根據(jù)不同的請求類型返回不同的值。
但是這里有一個問題:我們定義了 Method 類型只有兩種可能:GET 和 POST ,那么為什么還要寫 default 分支呢?因為這個分支永遠不會進入!
我們看一下 default 分支里是什么類型。
可以看到,它變成了 never 類型,這就得益于 TS 里的類型收縮,就是 TS 他會分析你的分支,根據(jù)你分支的條件來對類型做一個相應的收縮。
比如在下圖的分支里,就被收縮成了 GET 值,它就不在是聯(lián)合類型了。
那么在 default 里由于這個分支永遠不會進來,所以說它就用類型 never 來表示了。
那么這個對我們實際開發(fā)到底有什么用呢?
我們考慮這么一種情況,如果我們不寫 default 分支,我們對 Method 類型擴展了其他可能性,比如:PUT 或者 DELETE 等。
你看,在下圖中我們加了一個 PUT 類型以后,并沒有報錯,你壓根就不知道這個函數(shù)里還應該加一個 PUT 分支。
當你的代碼寫多了,然后再非常繁雜的代碼里邊,改了一個類型,你就很難知道,你這個改動會影響到哪些地方。
就是其他地方的代碼到底哪些地方會做相應的修改,你是很難知道的。
當然這個代碼很少,一眼就能看出來,那如果是上萬行代碼呢?因為 TS 往往是在大型項目工程中使用的,幾萬行代碼你還能清楚的知道嗎?
這個時候呢,我們就可以借助 never 了,來看下怎么做。
type Method = 'GET' | 'POST' function request(method: Method, url: string) { switch (method) { case "GET": return "get" case "POST": return "post" default: const n: never = method; return n } }
我們回到最初的情況,我們就加一個 default 分支,分支里定一個變量 n,標注為 never 類型,然后吧 method 賦值給它,然后返回這個 n。
它不會影響代碼的執(zhí)行,因為這個分支永遠進不來。
而且這個賦值也是安全的,因為現(xiàn)在 default 分支里的 method 是 never 類型,never 是可以賦值給 never 的,但是其他類型就不能賦值給 never 了。
接下來我們就可以放心大膽的去修改類型了。
當我們加了一個 PUT 以后,就會發(fā)現(xiàn)報錯了,因為 TS 的類型收縮,它知道分支里還有一種情況,就是 PUT,那么這種類型是不能賦值給 never 的,于是這里就報錯了。
這樣子呢,你就非常清楚這個地方還需要去增加一個分支,要做相應的修改。
比如說有很多這個函數(shù),根據(jù)報錯,就能很清楚的知道哪些地方要做修改了。
這是 never 類型在 TS 里邊非常常見的一種做法,這種做法在大型項目里邊及其有用。
總結
本文主要就是幫助你理解 never 類型在 TypeScript 中的應用及其優(yōu)勢。
在 TypeScript 中,never 類型表示一個永遠不會出現(xiàn)的值,它可以在類型收縮時進行自動推導,使代碼更加穩(wěn)定可靠。
在函數(shù)中,我們可以利用 never 類型來確保類型約束的精確性,避免了在類型修改過程中導致的錯誤。特別是在大型項目中,never 類型可以幫助我們更好地維護代碼,減少因修改類型而導致代碼修改和錯誤的風險。
例如,我們文章中的例子,通過分析代碼分支,我們可以使用 never
類型來標記永遠不會進入的分支。這樣一來,我們在以對類型進行擴展時,就可以很快地知道在哪些地方需要進行相應的修改,從而提高代碼的可維護性和穩(wěn)定性。
在項目開發(fā)中,特別是大型項目開發(fā)中,掌握使用 never 類型的技巧,可以讓同學們更加高效、精準地編寫出高質量的代碼。
以上就是TypeScript中never類型的妙用詳解的詳細內容,更多關于TypeScript never類型的資料請關注腳本之家其它相關文章!
相關文章
Java中int與integer的區(qū)別(基本數(shù)據(jù)類型與引用數(shù)據(jù)類型)
這篇文章主要介紹了int與integer的區(qū)別(基本數(shù)據(jù)類型與引用數(shù)據(jù)類型),簡單的說 int 是基本數(shù)據(jù)類型,integer 是引用數(shù)據(jù)類型,具體區(qū)別詳解大家參考下本文2017-02-02ES6新增數(shù)據(jù)結構WeakSet的用法詳解
WeakSet和Set類似,同樣是元素不重復的集合,它們的區(qū)別是WeakSet內的元素必須是對象,不能是其它類型。接下來通過本文給大家詳細介紹ES6新增數(shù)據(jù)結構WeakSet的用法,感興趣的朋友一起看看吧2017-08-08js for循環(huán),為什么一定要加var定義i變量
我知道,有些人(譬如之前的我)寫js的for循環(huán)時,都不習慣加上var,這當然是語法允許的。2010-06-06