自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從 React 源碼的類型定義中,我學到了什么?

開發(fā) 前端
React 類型定義做的挺完善的,考慮到了各種類型的處理,也考慮到了低版本的兼容,從中還是能學到不少東西的。

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

這篇文章就分享下這些寫法,估計大部分人都不知道:

提取可選索引的值

首先,我看到了這樣一段類型邏輯:

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

簡化一下就是這樣的:

提取 Props 的 ref 索引的值的類型返回。

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

于是我就改成了這樣:

然后試了下:

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

那就 Exclude 下不就行了:

這樣也比那個 infer 的方式簡潔呀,為啥 React 類型定義都是用的 infer 取的可選索引的類型呢?

后來我突然想到,如果這個 ref 值的類型就是 undefined 呢?

我試了下:

確實,我那樣寫是有問題的,如果值的類型本來就是 undefined,Exclude 掉 undefined 后就是 never 了,而人家那種方式就沒問題:

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

這樣就行了。

對比了下兩種寫法:

確實還是 React 的那種寫法更簡潔。

對了,那上面那層判斷呢?

這個判斷沒必要的吧,如果沒有 ref,那 Props['ref'] 不就是返回 never 么,沒必要單獨判斷呀?

然后我就看到了這樣一段注釋:

在 ts 3.0 中,如果索引類型沒有對應的索引,那返回的類型是 {} 而不是 never。

原來如此,這個 'ref' extends keyof Props 是為了做兼容的呀,不是沒意義。

這就是我從這個類型中學到的兩個知識點:

  • 索引訪問 Obj[Key] 和 infer 提取和都可以取到索引類型的某個索引的值,但是當處理可選索引的時候,用 infer 更簡潔一些,因為前者要取出類型之后再單獨處理下 undefined,而后者在 infer 的時候就順便處理了 undefined。
  • ts 3.0 中如果索引類型沒有對應的索引,返回的是 {} 不是 never,如果對兼容性要求高的話,可以用 'xx' in keyOf Obj 的方式做下兼容。

我們從這個類型里學到了不少東西,再來看下第二個類型:

索引類型和 any、never 的處理

然后我又看到了這樣一個類型,

先試一下它的功能,傳入兩個索引類型:

看下結果:

這是些啥啊,誰能看得懂呀。

其實這只是因為 TS 沒有計算出最終的類型而已,用到的時候才會計算,所以我們可以這樣處理下:

Copy 的高級類型是通過映射類型的語法構造了一個新的索引類型,它的功能是原封不動的復制一個索引類型。

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

因為重新生成的類型的過程中要做計算,所以那個類型就能提示出最終的結果了:

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

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

我們先來過一下 TS 這些內置的高級類型:

Pick

Pick 的作用是通過映射類型的語法構造一個新的索引類型,根據傳入的 Key 對索引做下過濾:

type Pick<T, K extends keyof T> = { [P in K]: T[P]; };

測試下:

Partial

Partial 也是通過映射類型的語法構造一個新的索引類型,但是會把索引變?yōu)榭蛇x:

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

測試下:

Extract

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

type Extract = T extends U ? T : never;

測試下:

Exclude

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

type Extract = T extends U ? T : never;

測試下:

學會了用 Pick、Partial、Exclude、Extract 這些高級類型,那上面的那段邏輯我們就知道怎么實現(xiàn)了:

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

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

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

這樣,這個類型的主要邏輯我們就理清了:

把三部分計算結果的索引類型取交叉類型,就會合并到一起。

那前面那兩個判斷是啥?

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

P extends any 這個是因為聯(lián)合類型當作為類型參數(shù)出現(xiàn)在條件類型左邊時,會把每個類型單獨傳入做計算,最后把計算結果合并成聯(lián)合類型,這個特性叫做分布式條件類型。

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

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

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

type UppercaseA<Item extends string> = 
Item extends 'a' ? Uppercase<Item> : Item;

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

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

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

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

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

什么類型的 keyof 結果是 string 呢?

突然,我想起了前幾天學到的一個知識點:用 keyof any 代替 string | number | symbol 更靈活:

而且我試了下 never 的 keyof 結果也是這個:

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

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

所以說,這個類型的邏輯我們已經理清了:

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

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

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

這個類型里我們也學到了不少東西。

總結

我看了下 @types/react 的類型定義,學到了不少東西:

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

而且,還講了一個小技巧:

ts 類型只有計算的時候才會求值,如果是索引類型,可以用映射類型的語法創(chuàng)建個一摸一樣的索引類型,因為用到了,就會做計算,從而就可以顯示出最終的類型。

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

責任編輯:姜華 來源: 神光的編程秘籍
相關推薦

2021-03-09 09:55:02

Vuejs前端代碼

2021-04-15 08:15:27

Vue.js源碼方法

2020-10-30 12:40:04

Reac性能優(yōu)化

2020-12-31 10:47:03

開發(fā)Vuejs技術

2016-01-18 10:06:05

編程

2020-02-22 15:01:51

后端前端開發(fā)

2021-01-02 09:48:13

函數(shù)運算js

2021-03-13 11:23:51

源碼邏輯框架

2024-04-12 08:54:13

從庫數(shù)據庫應用

2020-09-25 06:32:25

前端

2021-10-25 05:43:40

前端技術編程

2021-07-28 07:01:09

薅羊毛架構Vue+SSR

2020-02-22 14:49:30

畢業(yè)入職半年感受

2020-11-04 07:13:57

數(shù)據工程代碼編程

2023-10-16 08:55:43

Redisson分布式

2023-11-29 07:29:28

ReactSolid

2011-10-18 11:43:25

UNIXC語言丹尼斯·里奇

2019-11-20 09:00:52

Linux 開發(fā)操作系統(tǒng)

2023-04-10 07:40:36

GraphQLRest通信模式

2020-07-06 15:24:50

技術人工智能面試
點贊
收藏

51CTO技術棧公眾號