成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

TS 類型編程:索引類型遞歸去掉可選修飾

開發(fā) 前端
想取一個可選索引的值,需要先用 Required 把索引類型去掉可選然后再取。但是當(dāng)層數(shù)多了的話,這樣一層層處理挺麻煩的,可以用類型編程遞歸處理下。

這兩天東東遇到一個 TS 的問題,跑來問我。

問題是這樣的:

這樣一個 interface,想取出 userInfo 的類型來:

interface Result{
data?: {
userInfo?: {
name: string;
}
}
}

他是這樣取的:

type userInfo = Result['data']['userInfo'];

但是會報錯:

圖片

說是 userInfo 不在這個聯(lián)合類型上。

這很正常,因為可選索引的含義就是值和 undefined 的聯(lián)合類型  value | undefined。

于是他問我應(yīng)該怎么取?

我和他說這個問題有兩種不同復(fù)雜度的解決方案,有簡單的有復(fù)雜的,問他想聽哪個。

他說想聽簡單的,于是我告訴他這樣寫:

type userInfo = Required<Required<Result>['data']>['userInfo']

Required 是 ts 內(nèi)置的高級類型,是把索引類型的所有可選修飾去掉的。

圖片

所以每一層用 Required 處理一下再取索引的值就可以了。

但是這樣雖然簡單,當(dāng)取的層數(shù)多了要寫很多次 Required,也挺麻煩的。

然后東東又問我如果是復(fù)雜的那個,要怎么寫?

我和他說復(fù)雜的那個寫起來麻煩一些,但好處是用起來簡單,不管多少層都只需要處理一次:

首先要知道 Required 是怎么實現(xiàn)的:

圖片

他這里用到了映射類型的語法,作用是對索引類型做一些修改,生成新的索引類型。

P in keyof T 就是遍歷索引類型 T 中的所有索引 P,用來構(gòu)造新的索引類型,值保持不變,也就是 T[P]。

構(gòu)造的過程中可以加上可選的修飾、也可以去掉可選的修飾,還可以對值和索引做一些修改。

所以和 Required 相對的 Partial 就是這樣實現(xiàn)的:

圖片

我們想一次處理完所有層級,都把可選的修飾給去掉,那就要遞歸處理,也就是這樣:

type DeepRequired<Obj> = {
[Key in keyof Obj]-?: IsOptional<Key, Obj> extends never? Obj[Key]: DeepRequired<Obj[Key]>
}

遍歷索引類型 Obj 中的所有索引 Key,通過 -? 去掉可選,然后對值要做一下判斷,如果還是可選索引,那就遞歸處理。

那怎么實現(xiàn)這個 IsOptional 的判斷索引是否是可選的高級類型呢?

判斷某個類型要根據(jù)他的性質(zhì)來,可選的性質(zhì)就是 value | undefined,也就是說可能是空。

可以這樣來實現(xiàn)可選的判斷:

type IsOptional<Key extends keyof Obj, Obj> = 
{} extends Pick<Obj, Key> ? Key : never;

Obj 是索引類型,Key 是他的某個索引,因為可選索引的性質(zhì)是可能為空,所以 {} 就可能是索引類型的子類型。

這里的 Pick 也是內(nèi)置的高級類型,作用是取出一部分索引構(gòu)造新的索引類型:

圖片

同樣是通過映射類型的語法實現(xiàn)的:

圖片

這里 a 可能是沒有的,那當(dāng)沒有的時候不就是 {} 么?所以可以用 {} extends Pick<Obj, Key> 來判斷是不是可選索引。

綜上,遞歸去掉索引類型的可選修飾就是這樣實現(xiàn)的:

type IsOptional<Key extends keyof Obj, Obj> = 
{} extends Pick<Obj, Key> ? Key : never;

type DeepRequired<Obj> = {
[Key in keyof Obj]-?: IsOptional<Key, Obj> extends never? Obj[Key]: DeepRequired<Obj[Key]>
}

我們測試一下:

圖片

現(xiàn)在只要處理一次,就可以取任意層級的索引值了,方便了很多。

其實寫成這樣就可以用了,但是有時候你會遇到這樣的問題:

圖片

TS 沒有把最終的結(jié)果計算出來。

這個是 TS 的機制,默認是懶計算的,用不到的不會計算。

那怎么讓他計算出最終結(jié)果呢?

加上一段邏輯觸發(fā)計算就可以了,比如 xxx extends any 這種肯定會成立的條件判斷:

圖片

再測試一下你就會發(fā)現(xiàn) TS 計算出了最終的結(jié)果:

圖片

總結(jié)

想取一個可選索引的值,需要先用 Required 把索引類型去掉可選然后再取。但是當(dāng)層數(shù)多了的話,這樣一層層處理挺麻煩的,可以用類型編程遞歸處理下。

用映射類型的語法去掉索引類型的可選修飾,判斷值的類型,如果還是可選的索引,那就繼續(xù)遞歸的處理。

判斷可選索引是通過可選的性質(zhì)來的,可選索引的值是 value | undefined, 所以 {} extends Pick<Obj, Key> 成立的話就代表這個 Key 是可選的。

可能會遇到類型沒有全部計算的問題,這是 TS 的機制,默認是懶計算的,可以加上 xx extends any 這種不影響結(jié)果的條件類型來觸發(fā)計算。

層層用 Required 處理在層數(shù)少的情況下比較簡單,但層數(shù)多了的時候還是遞歸處理更方便一些,而且這樣的高級類型是可以復(fù)用的,可以用在別的地方,這也是類型編程的好處。

責(zé)任編輯:姜華 來源: 神光的編程秘籍
相關(guān)推薦

2022-01-19 23:41:56

TS索引類型

2024-01-16 07:33:02

SwiftTypeScript可選綁定

2015-09-02 10:33:54

紅包類型optionals

2022-02-12 22:16:53

TypeScript類型字符串

2010-10-26 17:34:03

Oracle索引

2024-07-08 10:48:51

2010-10-08 13:53:14

2022-05-07 07:33:55

TypeScript條件類型

2022-12-30 08:08:30

2022-08-08 23:49:01

TypeScriptumd模塊

2022-04-29 06:54:48

TS 映射類型User 類型

2022-02-25 14:04:56

TS前端代碼

2022-04-17 10:29:10

TSTypeScript對象類型

2011-11-03 16:32:57

Dart

2010-05-11 10:36:13

MySQL索引類型

2010-10-12 13:14:11

mysql索引類型

2010-11-02 11:22:06

DB2索引類型

2022-03-25 10:38:40

索引MySQL數(shù)據(jù)庫

2015-08-03 17:03:29

swiftoptionals可選型

2024-12-30 09:03:09

點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 97国产一区二区精品久久呦 | 欧美一区中文字幕 | 瑟瑟视频在线看 | www.亚洲| 超碰电影| 五月婷亚洲 | 亚洲国产精品一区二区第一页 | 国产精品视频一二三 | 日韩电影免费观看中文字幕 | 欧美黑人一区二区三区 | 成人免费网站在线 | 欧美一区二区免费 | 欧美日韩一二区 | 久久久妇女国产精品影视 | 天天操操 | 免费激情| 欧美精品1区2区3区 精品国产欧美一区二区 | 久草a√| 久久久久久久久精 | 成人免费黄色片 | 免费毛片网站 | 久久久精| 97综合在线 | 亚洲综合字幕 | 国产视频第一页 | 懂色一区二区三区免费观看 | 黄网站在线播放 | 久久精品国产一区二区电影 | 播放一级黄色片 | 涩涩导航 | 国产在线永久免费 | 国产亚洲精品久久久久久牛牛 | 99re视频在线观看 | 二区三区视频 | 亚洲电影一区二区三区 | 黄色一级特级片 | 在线播放第一页 | 日韩久久精品 | 午夜在线免费观看视频 | 久久不卡区 | 欧美成人aaa级毛片在线视频 |