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