日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
從React源碼的類(lèi)型定義中,我學(xué)到了什么?

今天看了下 React 的類(lèi)型定義,也就是 @types/react 包下的 index.d.ts,發(fā)現(xiàn)了一些有趣的寫(xiě)法。

這篇文章就分享下這些寫(xiě)法,估計(jì)大部分人都不知道:

提取可選索引的值

首先,我看到了這樣一段類(lèi)型邏輯:

這段邏輯就是取索引類(lèi)型的 ref 索引的值,但是是通過(guò)模式匹配的方式,把提取的類(lèi)型放到 infer 聲明的局部變量 R 里返回的。

簡(jiǎn)化一下就是這樣的:

提取 Props 的 ref 索引的值的類(lèi)型返回。

我在想,這么麻煩干什么,直接 Props['ref'] 不就能拿到 ref 索引的值么?

于是我就改成了這樣:

然后試了下:

不對(duì)呀,人家這是可選索引,值的類(lèi)型是包含 undefined 的聯(lián)合類(lèi)型。

那就 Exclude 下不就行了:

這樣也比那個(gè) infer 的方式簡(jiǎn)潔呀,為啥 React 類(lèi)型定義都是用的 infer 取的可選索引的類(lèi)型呢?

后來(lái)我突然想到,如果這個(gè) ref 值的類(lèi)型就是 undefined 呢?

我試了下:

確實(shí),我那樣寫(xiě)是有問(wèn)題的,如果值的類(lèi)型本來(lái)就是 undefined,Exclude 掉 undefined 后就是 never 了,而人家那種方式就沒(méi)問(wèn)題:

于是我就加一下 undefined 的處理:

這樣就行了。

對(duì)比了下兩種寫(xiě)法:

確實(shí)還是 React 的那種寫(xiě)法更簡(jiǎn)潔。

對(duì)了,那上面那層判斷呢?

這個(gè)判斷沒(méi)必要的吧,如果沒(méi)有 ref,那 Props['ref'] 不就是返回 never 么,沒(méi)必要單獨(dú)判斷呀?

然后我就看到了這樣一段注釋?zhuān)?/p>

在 ts 3.0 中,如果索引類(lèi)型沒(méi)有對(duì)應(yīng)的索引,那返回的類(lèi)型是 {} 而不是 never。

原來(lái)如此,這個(gè) 'ref' extends keyof Props 是為了做兼容的呀,不是沒(méi)意義。

這就是我從這個(gè)類(lèi)型中學(xué)到的兩個(gè)知識(shí)點(diǎn):

  • 索引訪問(wèn) Obj[Key] 和 infer 提取和都可以取到索引類(lèi)型的某個(gè)索引的值,但是當(dāng)處理可選索引的時(shí)候,用 infer 更簡(jiǎn)潔一些,因?yàn)榍罢咭〕鲱?lèi)型之后再單獨(dú)處理下 undefined,而后者在 infer 的時(shí)候就順便處理了 undefined。
  • ts 3.0 中如果索引類(lèi)型沒(méi)有對(duì)應(yīng)的索引,返回的是 {} 不是 never,如果對(duì)兼容性要求高的話,可以用 'xx' in keyOf Obj 的方式做下兼容。

我們從這個(gè)類(lèi)型里學(xué)到了不少東西,再來(lái)看下第二個(gè)類(lèi)型:

索引類(lèi)型和 any、never 的處理

然后我又看到了這樣一個(gè)類(lèi)型,

先試一下它的功能,傳入兩個(gè)索引類(lèi)型:

看下結(jié)果:

這是些啥啊,誰(shuí)能看得懂呀。

其實(shí)這只是因?yàn)?TS 沒(méi)有計(jì)算出最終的類(lèi)型而已,用到的時(shí)候才會(huì)計(jì)算,所以我們可以這樣處理下:

Copy 的高級(jí)類(lèi)型是通過(guò)映射類(lèi)型的語(yǔ)法構(gòu)造了一個(gè)新的索引類(lèi)型,它的功能是原封不動(dòng)的復(fù)制一個(gè)索引類(lèi)型。

類(lèi)型參數(shù) Obj 約束為索引類(lèi)型,也就是 Record。key 保持不變,也就是 Key in keyof Obj,value 也保持不變,也就是 Obj[Key]。

因?yàn)橹匦律傻念?lèi)型的過(guò)程中要做計(jì)算,所以那個(gè)類(lèi)型就能提示出最終的結(jié)果了:

所以說(shuō),這個(gè)類(lèi)型的作用是兩個(gè)索引類(lèi)型 A,B,只有 A 中有的就保留,A、B 都有的變?yōu)榭蛇x,B 有但 A 沒(méi)有的變?yōu)榭蛇x。

那這段邏輯具體是怎么用 TS 實(shí)現(xiàn)的呢?

我們先來(lái)過(guò)一下 TS 這些內(nèi)置的高級(jí)類(lèi)型:

Pick

Pick 的作用是通過(guò)映射類(lèi)型的語(yǔ)法構(gòu)造一個(gè)新的索引類(lèi)型,根據(jù)傳入的 Key 對(duì)索引做下過(guò)濾:

type Pick = { [P in K]: T[P]; };

測(cè)試下:

Partial

Partial 也是通過(guò)映射類(lèi)型的語(yǔ)法構(gòu)造一個(gè)新的索引類(lèi)型,但是會(huì)把索引變?yōu)榭蛇x:

type Partial = { [P in keyof T]?: T[P]; };

測(cè)試下:

Extract

Extract 是取兩個(gè)聯(lián)合類(lèi)型都包含的部分,也就是取交集:

type Extract = T extends U ? T : never;

測(cè)試下:

Exclude

Exclude 是從聯(lián)合類(lèi)型 A 中去掉聯(lián)合類(lèi)型 B 中的類(lèi)型,也就是取差集:

type Extract = T extends U ? T : never;

測(cè)試下:

學(xué)會(huì)了用 Pick、Partial、Exclude、Extract 這些高級(jí)類(lèi)型,那上面的那段邏輯我們就知道怎么實(shí)現(xiàn)了:

只有 A 中有的就保留的邏輯是:Pick>。

A、B 都有的變?yōu)榭蛇x:Partial>>。

B 中有但 A 中沒(méi)有的也變?yōu)榭蛇x:Partial>>。

這樣,這個(gè)類(lèi)型的主要邏輯我們就理清了:

把三部分計(jì)算結(jié)果的索引類(lèi)型取交叉類(lèi)型,就會(huì)合并到一起。

那前面那兩個(gè)判斷是啥?

P extends any 還有這個(gè) string extends keyof P,這倆都是做啥的?

P extends any 這個(gè)是因?yàn)槁?lián)合類(lèi)型當(dāng)作為類(lèi)型參數(shù)出現(xiàn)在條件類(lèi)型左邊時(shí),會(huì)把每個(gè)類(lèi)型單獨(dú)傳入做計(jì)算,最后把計(jì)算結(jié)果合并成聯(lián)合類(lèi)型,這個(gè)特性叫做分布式條件類(lèi)型。

比如這樣一個(gè)聯(lián)合類(lèi)型:

type Union = 'a' | 'b' | 'c';

我們想把其中的 a 大寫(xiě),就可以這樣寫(xiě):

type UppercaseA = 
Item extends 'a' ? Uppercase : Item;

因?yàn)?Item 是類(lèi)型參數(shù),出現(xiàn)在了條件類(lèi)型的左邊,而且傳入的是聯(lián)合類(lèi)型,那就觸發(fā)分發(fā)特性,會(huì)把每個(gè)類(lèi)型單獨(dú)傳入做計(jì)算,然后把結(jié)果合并成聯(lián)合類(lèi)型。

所以這里的 P extends any 的作用就是觸發(fā)聯(lián)合類(lèi)型特性的,從而讓這個(gè)類(lèi)型能正確處理聯(lián)合類(lèi)型。不然聯(lián)合類(lèi)型整個(gè)傳入的話,后面怎么做計(jì)算。

這里的 P extends any 換成 P extends P 也可以,都是一樣的作用。

那后面那段代碼 string extends keyof P 是啥意思?

這個(gè)我確實(shí)想了一段時(shí)間,如果 { a: 1, b: 2} 這樣的索引類(lèi)型,keyof 的結(jié)果是 'a' | 'b',而如果是數(shù)組類(lèi)型,那 keyof 的結(jié)果是 0 | 1 | 'length' | 'toString' | ...

什么類(lèi)型的 keyof 結(jié)果是 string 呢?

突然,我想起了前幾天學(xué)到的一個(gè)知識(shí)點(diǎn):用 keyof any 代替 string | number | symbol 更靈活:

而且我試了下 never 的 keyof 結(jié)果也是這個(gè):

所以說(shuō) string extends keyof P 就可以排除 any 和 never 的情況!

妙呀,還能這么區(qū)分 any 和 never。

所以說(shuō),這個(gè)類(lèi)型的邏輯我們已經(jīng)理清了:

這個(gè)類(lèi)型的功能是保留只有 A 有的索引,把 A、B 都有的索引變?yōu)榭蛇x,把只有 B 有的索引變?yōu)榭蛇x。

而且處理了聯(lián)合類(lèi)型的情況。

如果傳入的是 any 或者 never,不做處理,直接返回。

這個(gè)類(lèi)型里我們也學(xué)到了不少東西。

總結(jié)

我看了下 @types/react 的類(lèi)型定義,學(xué)到了不少東西:

  • 可選索引的值的提取,用 infer 比 Obj[key] 更方便,因?yàn)榍罢咧恍枰?Obj[Key] extends { xxx?: infer Value: undefined},而后者需要先排除值的類(lèi)型就是 undefined 的情況,然后再用 Exclude 去掉類(lèi)型中的 undefined。
  • ts 3.0 中取索引類(lèi)型沒(méi)有的索引會(huì)返回 {} 而不是 never,需要兼容的話可以單獨(dú)做下判斷:'xxx' in keyof Obj。
  • 處理索引類(lèi)型可以綜合用 Pick、Partial、Exclude、Extract 等內(nèi)置高級(jí)類(lèi)型對(duì)每一部分索引做處理,然后取交叉類(lèi)型來(lái)合并到一起。
  • P extends any 和 P extends P 的作用是觸發(fā)聯(lián)合類(lèi)型的分發(fā)特性的,加上這段處理才能正確處理聯(lián)合類(lèi)型,會(huì)把每個(gè)類(lèi)型單獨(dú)傳入做計(jì)算,最后把結(jié)果合并成聯(lián)合類(lèi)型。
  • string extends keyof Obj 可以判斷出 any 和 never 類(lèi)型,只有這兩種類(lèi)型取 keyof 的結(jié)果是 string | nubmer | symbole,包含 string。

而且,還講了一個(gè)小技巧:

ts 類(lèi)型只有計(jì)算的時(shí)候才會(huì)求值,如果是索引類(lèi)型,可以用映射類(lèi)型的語(yǔ)法創(chuàng)建個(gè)一摸一樣的索引類(lèi)型,因?yàn)橛玫搅?,就?huì)做計(jì)算,從而就可以顯示出最終的類(lèi)型。

不得不說(shuō),React 類(lèi)型定義做的挺完善的,考慮到了各種類(lèi)型的處理,也考慮到了低版本的兼容,從中還是能學(xué)到不少東西的。


網(wǎng)頁(yè)名稱(chēng):從React源碼的類(lèi)型定義中,我學(xué)到了什么?
瀏覽路徑:http://m.5511xx.com/article/ccsjcso.html