前言
在群里看到一些問(wèn)題和言論:為什么你們這么喜歡“類(lèi)型體操”?為什么我根本學(xué)不下去 TypeScript?我最討厭那些做類(lèi)型體操的了;為什么我學(xué)了沒(méi)過(guò)多久馬上又忘了?
有感于這些問(wèn)題,我想從最簡(jiǎn)單的一個(gè)角度來(lái)切入介紹一下 TypeScript,并向大家介紹并不是只要是個(gè)類(lèi)型運(yùn)算就是體操。并在文中介紹一種基本思想作為你使用類(lèi)型系統(tǒng)的基本指引。
引子
我將從一個(gè)相對(duì)簡(jiǎn)單的 API 的設(shè)計(jì)過(guò)程中闡述關(guān)于類(lèi)型的故事。在這里我們可以假設(shè)我們現(xiàn)在是一個(gè)工具的開(kāi)發(fā)者,然后我們需要設(shè)計(jì)一個(gè) API 用于從對(duì)象中拿取指定的一些 key 作為一個(gè)新的對(duì)象返回給外面使用。
垃圾 TypeScript
一個(gè)人說(shuō):我才不用什么破類(lèi)型,我寫(xiě)代碼就是要沒(méi)有類(lèi)型,我就是要隨心所欲的寫(xiě)。然后寫(xiě)下了這段代碼。
declarefunctionpick(target:any,...keys:any):any
他的用戶(hù)默默的寫(xiě)下了這段代碼:
pick(undefined,'a',1).b
寫(xiě)完運(yùn)行,發(fā)現(xiàn)問(wèn)題大條了,控制臺(tái)一堆報(bào)錯(cuò),接口數(shù)據(jù)也提交不上去了,怎么辦呢?
剛學(xué) TypeScript
一個(gè)人說(shuō):稍微檢查一下傳入類(lèi)型就好了,別讓人給我亂傳參數(shù)就行。
declarefunctionpick(target:Record,...keys:string[]):unknown
很好,上面的問(wèn)題便不復(fù)存在了,API 也是基本可用的了。但是!當(dāng)對(duì)象復(fù)雜的時(shí)候,以及字段并不是短單詞長(zhǎng)度的時(shí)候就會(huì)發(fā)現(xiàn)了一個(gè)沒(méi)解決的問(wèn)題。
pick({abcdefghijkl:'123'},'abcdefghikjl')
從肉眼角度上,我們很難發(fā)現(xiàn)這前后的不一致,所以我們?yōu)槭裁匆屨{(diào)用方的用戶(hù)自己去 check 自己的字段有沒(méi)有寫(xiě)對(duì)呢?
不就 TypeScript
一個(gè)人說(shuō):這還不簡(jiǎn)單,用個(gè)泛型加 keyof 不就行了。
declarefunctionpick< ??T?extends?Record>(target:T,...keys:(keyofT)[]):unknown
我們又進(jìn)一步解決的上面的問(wèn)題,但是!還是有著相似的問(wèn)題,雖然我們不用檢查 keys 是不是傳入的是一個(gè)正確的值了,但是我們實(shí)際上對(duì)返回的值也存在一個(gè)類(lèi)似的問(wèn)題。
pick({abcdefghijkl:'123'},'abcdefghijkl').abcdefghikjl
一點(diǎn)小小的拓展
在這里我們看起來(lái)似乎是一個(gè)很簡(jiǎn)單的功能,但實(shí)際上蘊(yùn)含著一個(gè)比較重要的信息。
為什么我們之前的方式都拿不到用戶(hù)傳入進(jìn)來(lái)的類(lèi)型信息呢?是有原因的,當(dāng)我們?cè)O(shè)計(jì)的 API 的時(shí)候,前面的角度是從,如何校驗(yàn)類(lèi)型方向進(jìn)行的思考。
而這里是嘗試去通過(guò)約定好的一種規(guī)則,通過(guò) TypeScript 的隱式類(lèi)型推斷獲得到傳入的類(lèi)型,再通過(guò)約定的規(guī)則轉(zhuǎn)化出一種新的類(lèi)型約束來(lái)對(duì)用戶(hù)的輸入進(jìn)行限制。
算算 TypeScript
一個(gè)人說(shuō):好辦,算出來(lái)一個(gè)新的類(lèi)型就好了。
declarefunctionpick< ??T?extends?Record, KeysextendskeyofT >(target:T,...keys:Keys[]):{ [KinKeys]:T[K] }
到這里已經(jīng)是對(duì)類(lèi)型的作用有了基礎(chǔ)的了解了,能寫(xiě)出來(lái)符合開(kāi)發(fā)者所能接受的類(lèi)型相對(duì)友好的代碼了。我們可以再來(lái)思考一些更特殊的情況:
//輸入了重復(fù)的key pick({a:''},'a','a')
完美 TypeScript
到這里,我們便是初步開(kāi)始了類(lèi)型“體操”。但是在本篇里,我們不去分析它。
exporttypeL2T=[L]extends[never] ?[] :LextendsinferLItem ?[LItem?,...L2T,LAlias>] :never declarefunctionpick< ??T?extends?Record, KeysextendsL2T >(target:T,...keys:Keys):Pick constx0=pick({a:'1',b:'2'},'a') console.log(x0.a) //@ts-expect-error console.log(x0.b) constx1=pick({a:'1',b:'2'},'a','a') //^^^^^^^^ //TS2345:Argumentoftype'["a","a"]'isnotassignabletoparameteroftype'["a"?,"b"?]|["b"?,"a"?]'. //Type'["a","a"]'isnotassignabletotype'["a"?,"b"?]'. //Typeatposition1insourceisnotcompatiblewithtypeatposition1intarget. //Type'"a"'isnotassignabletotype'"b"'.
一個(gè)相對(duì)來(lái)說(shuō)比較完美的 pick 函數(shù)便完成了。
總結(jié)
我們?cè)賮?lái)回到我們的標(biāo)題吧,從我對(duì)大多數(shù)人的觀察來(lái)說(shuō),很多的人開(kāi)始來(lái)使用 TypeScript 有幾種原因:
看到大佬們都在玩,所以自己也想來(lái)“玩”,然后為了過(guò)類(lèi)型校驗(yàn)而去寫(xiě)
看到一些成熟的項(xiàng)目在使用 TypeScript ,想?yún)⑴c貢獻(xiàn),參與過(guò)程中為了讓類(lèi)型通過(guò)而想辦法去解決類(lèi)型報(bào)錯(cuò)
公司整體技術(shù)棧采用的是 TypeScript ,要用 TypeScript 進(jìn)行業(yè)務(wù)編寫(xiě),從而為了過(guò)類(lèi)型檢查和 review 而去解決類(lèi)型問(wèn)題
諸如此類(lèi)的問(wèn)題還有很多,我將這種都劃分為「為了解決類(lèi)型檢查的問(wèn)題」而進(jìn)行的類(lèi)型編程,這也是大多數(shù)人為什么非常不適應(yīng) TypeScript,甚至不喜歡他的一個(gè)原因。這其實(shí)對(duì)學(xué)習(xí) TypeScript 并不是一個(gè)很好的思路,在這里我覺(jué)得我們需要站在設(shè)計(jì)者的角度去對(duì)類(lèi)型系統(tǒng)進(jìn)行思考。我覺(jué)得有以下幾個(gè)角度:
類(lèi)型檢查到位
類(lèi)型提示友好
類(lèi)型檢查嚴(yán)格
擴(kuò)展性十足
我們?nèi)绻驹谶@幾個(gè)角度對(duì)我們的 API 進(jìn)行設(shè)計(jì),我們可以發(fā)現(xiàn),開(kāi)發(fā)者能夠很輕松的將他們需要的代碼編寫(xiě)出來(lái),而盡量不用去翻閱文檔,查找 example。
希望通過(guò)我的這篇分享,大家能對(duì) TypeScript 多一些理解,并參與到生態(tài)中來(lái),守護(hù)我們的 JavaScript。
鏈接:https://juejin.cn/post/7248599585751515173
審核編輯:劉清
-
JAVA語(yǔ)言
+關(guān)注
關(guān)注
0文章
138瀏覽量
20090 -
javascript
+關(guān)注
關(guān)注
0文章
516瀏覽量
53851 -
java接口
+關(guān)注
關(guān)注
0文章
2瀏覽量
1165
原文標(biāo)題:為什么你非常不適應(yīng) TypeScript
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論