TS 類型體操合集

基本姿勢

keyof

keyof 返回一個類型的所有 key 的聯(lián)合類型:

type KEYS = keyof {
    a: string,
    b: number
} // a|b

類型索引

類型索引可以通過 key 來獲取對應 value 的類型:

type Value = {a: string, b: number}['a'] // string

特別的酣胀,使用 array[number] 可以獲取數(shù)組/元組中所有值類型的聯(lián)合類型:

type Values = ['a', 'b', 'c'][number] // 'a'|'b'|'c'

in 操作符與類型映射

in 操作符有點類似于值操作中的 for in 操作冯遂,可以遍歷聯(lián)合類型缠劝,結合類型索引可以從一個類型中生成一個新的類型:

// 從 T 中 pick 出一個或多個 key 組成新的類型
type MyPick<T, S extends keyof T> = {
    [R in S] : T[R]
} 
type PartType = MyPick<{a: string, b: number, c: number}, 'a'|'b'> // {a: string, b: number}

同樣狈究,數(shù)組類型也可以遍歷递递,R in keyof T 的結果為數(shù)組的下標:

type ArrayIndex<T extends any[]> = {
    [R in keyof T]: R
}
// 的到一個數(shù)組下標組成的新數(shù)組類型
type Indexes = ArrayIndex<['a', 'b', 'c']> // ['0', '1', '2']

extends

extends 類型于值運算符中的三元表達式:

S extends T ? K : V

若 S 兼容 T 則返回類型 K 否則返回類型 V算灸,例如:

type Whether = "a" extends "a"|"b" ? true : false // true
type Whether2 = {a: string} extends {b: string} ? true : false // false

extends 中有一個重要的概念為類型分發(fā)忿族,例如:

type Filter<T, S> = T extends S ? never : T
type X = Filter<'a'|'b'|'c', 'c'> // 'a'|'b'

從直觀上來看 Filter 的作用是計算 'a'|'b'|'c' extends 'c' 這個表達式顯然不成立锣笨,應該返回 never。但是實際上返回了 'a'|'b'道批。這是由于當 extends 需要檢測的類型為泛型聯(lián)合類型時错英,會將聯(lián)合類型中的每一個類型分別進行檢測。因此 'a'|'b'|'c' extends 'c' 實際等價于:

'a' extends 'c' ? never : T | 'b' extends 'c' ? never : T | 'c' extends 'c' ? never : T 
  = 'a' | 'b' | never 
  = 'a' | 'b' 

這里也包含了另外一個知識點隆豹,xxx|never=xxx椭岩。可以將聯(lián)合類型與 extends 結合使用達到循環(huán)的效果璃赡。如果要阻止類型分發(fā)判哥,只需要在外面套一個數(shù)組即可:

type Filter<T, S> = T extends S ? never : T
type X = Filter<'a'|'b'|'c', 'c'> // 'a'|'b'

type Filter<T, S> = [T] extends [S] ? never : T
type X = Filter<'a'|'b'|'c', 'c'> // never

如果很多時候我們既需要類型分發(fā)后的類型,還需要類型分發(fā)前的聯(lián)合類型碉考。例如如果我們判斷一個類型是否為聯(lián)合類型塌计,那么可以:

type IsUnion<T> = T extends T ? [Exclude<T, T>] extends [never] ? false: true : never

即如果一個類型是聯(lián)合類型,那么 execlude 掉一個其中的類型后其類型不會為 never侯谁。否則就為 never夺荒。但是在 Exclude 中出現(xiàn)了兩 T 這明顯是不行的瞒渠。因此可以利用 TS 的默認類型:

type IsUnion<T, R=T> = T extends any ? [Exclude<R, T>] extends [never] ? false: true : never

這種方法可以用在既需要分發(fā)后的類型也需要原始類型的情況。

此外技扼,extends 還有另一個需要注意的地方伍玖,泛型變量無法直接與 never 比較,需要套一個數(shù)組剿吻,例如:

type IsNever<T> = T extends never ? true: false
type Y = IsNever<never> // never

type IsNever<T> = [T] extends [never] ? true: false
type Y = IsNever<never> // true

infer

infer 可以類比到值元算的類型匹配窍箍,在類型體操中有非常多的應用。例如對于 scala:

a match {
case Success(val) => val
case _ => None
}

當 a 值為 Success() 類型時提取其中的 val丽旅。利用 infer 也可以達到相同的效果:

type ExtractType<T> = T extends {a: infer R} ? R : never // 匹配成功返回 R 否則返回 never
ExtractType<{a: {b: string}}> // {b: string}

可以看出先定義了一個模板 {a: infer R} 然后用于匹配類型 {a: {b: string}}椰棘,這時就可以得到 R = {b: string}。目前 infer 出來的類型僅能應用到 extends 的成功分支榄笙。
infer 也可以用匹配字面量的類型邪狞,例如:

type Startswith<T, S extends string> = T extends `${S}${infer R}` ? true : false
Startswith<"hello world", "hello"> // true
Startswith<"hello world", "world"> // false

type Strip<T, S extends string> = T extends `${S}${infer R}` ? R : T
type Y1 = Strip<"hello world", "hello "> // world
type Y2 = Strip<"hello world", "world"> // hello world

數(shù)組/元組類型

數(shù)組類型可以使用 ... 操作符進行展開:

type Add<S extends any[], R> = [...S, R]
type Y3 = Add<[1, 2, 3], 4> // [1, 2, 3, 4]

元組表示不可修改的數(shù)組,可以使用 as const 將數(shù)組轉換為元組茅撞。

const array1 = [1, 2, 3, 4]
type X1 = typeof array1 // number[]
type X2 = X1[number] // number

const array2 = [1, 2, 3, 4] as const
type Y1 = typeof array2 // readonly [1, 2, 3, 4]
type Y2 = Y1[number] // 1|2|3|4

遞歸類型

在 typescript 類型操作符中不存在循環(huán)表達式帆卓,但是可以使用遞歸來進行循環(huán)操作,例如:

type TrimLeft<T extends string> = T extends ` ${infer R}`? TrimLeft<R>: T
type Y7 = TrimLeft<'  Hello World  '> // Hello World  

type Concat<S extends any[]> = S extends [infer R, ...infer Y] ? `${R & string}${Concat<Y>}` : ''
type Y6 = Concat<['1', '2', '3']>

type Join<S extends any[], T extends string> = S extends [infer R, ...infer Y] ? 
                                                (Y['length'] extends 0 ? R: `${R & string}${T}${Join<Y, T>}`)  : ''
                                               
type Y4 = Join<['1', '2', '3'], '-'> // '1-2-3'


type Flatten<S extends any[]> = S extends [infer R, ...infer Y] ? 
    (R extends any[] ? [...Flatten<R>, ...Flatten<Y>] : [R, ...Flatten<Y>]) : []
type Y3 = Flatten<[[1], 2, [3, 4, [5], [6, [7, 8]]]]> // [1, 2, 3, 4, 5, 6, 7 ,8]
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末米丘,一起剝皮案震驚了整個濱河市剑令,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拄查,老刑警劉巖吁津,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異堕扶,居然都是意外死亡碍脏,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人舞箍,你說我怎么就攤上這事〖崩瑁” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵侧到,是天一觀的道長勃教。 經(jīng)常有香客問我,道長匠抗,這世上最難降的妖魔是什么故源? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮汞贸,結果婚禮上绳军,老公的妹妹穿的比我還像新娘印机。我一直安慰自己,他們只是感情好门驾,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布射赛。 她就那樣靜靜地躺著,像睡著了一般奶是。 火紅的嫁衣襯著肌膚如雪楣责。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天聂沙,我揣著相機與錄音秆麸,去河邊找鬼。 笑死及汉,一個胖子當著我的面吹牛沮趣,可吹牛的內容都是我干的。 我是一名探鬼主播坷随,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼房铭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了甸箱?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤迅脐,失蹤者是張志新(化名)和其女友劉穎芍殖,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谴蔑,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡豌骏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了隐锭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窃躲。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖钦睡,靈堂內的尸體忽然破棺而出蒂窒,到底是詐尸還是另有隱情,我是刑警寧澤荞怒,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布洒琢,位于F島的核電站,受9級特大地震影響褐桌,放射性物質發(fā)生泄漏衰抑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一荧嵌、第九天 我趴在偏房一處隱蔽的房頂上張望呛踊。 院中可真熱鬧砾淌,春花似錦、人聲如沸谭网。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜻底。三九已至骄崩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間薄辅,已是汗流浹背要拂。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留站楚,地道東北人脱惰。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像窿春,于是被迫代替她去往敵國和親拉一。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容