ts 類型體操之 easy 題

終于還是被通知解除合同了,只能全心投入到新的求職之路上去了歌憨。不過(guò)着憨,我還是想盡快完成《類型體操》系列文章,盡量每周都有產(chǎn)出务嫡。Easy 題共 13 題甲抖,題目都很短,我就全部整理到這一篇文章了植袍。

If

實(shí)現(xiàn)一個(gè)實(shí)用類型 If<C, T, F>惧眠,它接受一個(gè) boolean 類型 C,一個(gè)真值 T 和一個(gè)假值 F于个。若 C 是 true 返回 T氛魁;若 C 是 false 返回 F。

type A = If<true, 'a', 'b'>; // expected to be 'a'
type B = If<false, 'a', 'b'>; // expected to be 'b'

考點(diǎn):extends 的兩個(gè)用途:類型約束和條件判斷厅篓。

type If<C extends boolean, T, F> = C extends true ? T : F;
  • C extends boolean:約束類型 C 必須是 boolean 類型秀存。
  • C extends true:判斷 C 是否為 true 。

Tuple to Object

給定一個(gè)數(shù)組羽氮,將其轉(zhuǎn)換為對(duì)象類型或链,鍵/值必須在提供的數(shù)組中。

const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const;

type result = TupleToObject<typeof tuple>; // expected { 'tesla': 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}

考點(diǎn):數(shù)組(array)或元祖(tuple)類型有個(gè)number屬性档押,它可以把數(shù)組或元祖中的元素類型提取出來(lái)構(gòu)成聯(lián)合類型.

比如:

type Tuple = [string, number];
type TupleNum = Tuple[number]; // string | number

所以澳盐,我們可以利用這個(gè)特性,把數(shù)組(T)中的元素類型提取成聯(lián)合類型(T[number])令宿;然后通過(guò)《基礎(chǔ)語(yǔ)法》篇里提到的類型映射叼耙,用 in 遍歷該聯(lián)合類型,最后確保鍵/值一致粒没,就完成了這個(gè)題筛婉。

type TupleToObject<T extends readonly PropertyKey[]> = {
  [K in T[number]]: K;
};

p.s. 還記得 PropertyKey 是什么嗎?它是 string | number | symbol 的別名癞松。

Length of Tuple

獲取元祖的長(zhǎng)度爽撒。

如:

type tesla = ['tesla', 'model 3', 'model X', 'model Y'];
type spaceX = [
  'FALCON 9',
  'FALCON HEAVY',
  'DRAGON',
  'STARSHIP',
  'HUMAN SPACEFLIGHT',
];

type teslaLength = Length<tesla>; // expected 4
type spaceXLength = Length<spaceX>; // expected 5

考點(diǎn):數(shù)組類型有個(gè)length屬性入蛆,它表示該數(shù)組的長(zhǎng)度。用法和T[number]有點(diǎn)區(qū)別硕勿,length外要加個(gè)要引號(hào)——T['length']哨毁。

實(shí)現(xiàn)就很簡(jiǎn)單了,直接返回T['length']即可首尼。

type Length<T extends readonly any[]> = T['length'];

First of Array

從一個(gè)數(shù)組類型中獲取它的第一個(gè)類型挑庶。

如:

type arr1 = ['a', 'b', 'c'];
type arr2 = [3, 2, 1];

type head1 = First<arr1>; // expected to be 'a'
type head2 = First<arr2>; // expected to be 3

考點(diǎn):T[0]表示數(shù)據(jù)第一個(gè)元素,T[1]第二個(gè)软能,依次類推。如果 index 超出了數(shù)組長(zhǎng)度举畸,則返回undefined查排。

實(shí)現(xiàn)入下:

type First<T extends any[]> = T['length'] extends 0 ? never : T[0];

簡(jiǎn)單解釋一下:

  1. T extends any[]:限定 T 必須是一個(gè)數(shù)組類型
  2. T['length'] extends 0:判斷T['length']是否為0,如果T['length']不是抄沮,則表示大于0跋核,返回T[0]——即第一個(gè)元素,否則返回never叛买。

這里提一句T[number]本質(zhì)等于T[0] | T[1] | T[2] | ...砂代,所以它成了數(shù)組所有元素的聯(lián)合類型,而T['length']則是一個(gè)具體的數(shù)字率挣。

Concat

在類型系統(tǒng)中實(shí)現(xiàn) JavaScript 的 Array.concat 函數(shù)刻伊。該類型接受兩個(gè)數(shù)組參數(shù)。輸出一個(gè)新數(shù)組椒功,按從左到右的順序包含輸入內(nèi)容捶箱。

如:

type Result = Concat<[1], [2]>; // expected to be [1, 2]

考點(diǎn):... 擴(kuò)展運(yùn)算符(Spread syntax):它可以在數(shù)組構(gòu)造時(shí),將數(shù)組表達(dá)式在語(yǔ)法層面展開(kāi)动漾。

知道這個(gè)考點(diǎn)丁屎,答案就呼之欲出了。

type Concat<T extends readonly unknown[], U extends readonly unknown[]> = [
  ...T,
  ...U,
];

但是要注意:這個(gè)是類型系統(tǒng)的數(shù)組旱眯,不是 JS 的數(shù)組晨川;它們倆只有極少數(shù)的語(yǔ)法是相同的。學(xué)習(xí)類型系統(tǒng)删豺,還是要以學(xué)習(xí)新語(yǔ)言的態(tài)度去對(duì)待共虑。

下面再做兩道類似的題目。

Push

實(shí)現(xiàn) Array.push:在數(shù)組末尾追加一個(gè)元素

如:

type Result = Push<[1, 2], '3'>; // [1, 2, '3']

考點(diǎn): 還是擴(kuò)展運(yùn)算符

type Push<T extends readonly unknown[], U> = [...T, U];

Unshift

實(shí)現(xiàn) Array.unshift吼鳞,就是在數(shù)組的開(kāi)頭添加元素看蚜。

如:

type Result = Unshift<[1, 2], 0>; // [0, 1, 2]

做完 Push,這題就毫無(wú)壓力了赔桌。

type Unshift<T extends unknown[], U> = [U, ...T];

Includes

在類型系統(tǒng)中實(shí)現(xiàn) JavaScript 的 Array.includes 函數(shù)供炎。該類型接受兩個(gè)參數(shù)渴逻。輸出應(yīng)為布爾值 true 或 false。

如:

type isPillarMen = Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Dio'>; // expected to be `false`

考點(diǎn):1. 擴(kuò)展運(yùn)算符和 infer 的結(jié)合音诫;2. 遞歸

這題還是有點(diǎn)難度的惨奕,理論上不應(yīng)該是 easy 題。我們先看答案竭钝,再解釋:

type Includes<T extends readonly any[], U> = T extends [
  infer First,
  ...infer Rest,
]
  ? Equal<First, U> extends true
    ? true
    : Includes<Rest, U>
  : false;

逐行解釋:

  1. T extends [infer First, ...infer Rest]:我們使用擴(kuò)展運(yùn)算符梨撞,將數(shù)組 T 展開(kāi)為FirstRest兩部分。其中香罐,First是數(shù)組的第一個(gè)元素卧波,Rest是數(shù)組的剩余部分。這個(gè)語(yǔ)法大家要記住庇茫,之后的 medium 題里面會(huì)反復(fù)出現(xiàn)港粱。
  2. Equal<First, U> extends true ? true : Includes<Rest, U>:我們使用 infer 關(guān)鍵字推斷出 First 類型,接著將 First 和 U 進(jìn)行比較旦签。如果相等查坪,則返回 true;否則宁炫,遞歸調(diào)用 Includes偿曙,將剩余部分 Rest 和 U 進(jìn)行比較。
  3. : false:如果數(shù)組 T 為空羔巢,則返回 false望忆。

p.s.Equal 不是原生的 ts 類型方法;但是在 type challenge 里我通常都直接用朵纷。它的實(shí)現(xiàn)大大超出了本文 easy 的范疇炭臭,我會(huì)在之后 hard 篇章里解釋,這里先把它的實(shí)現(xiàn)列一下袍辞,有興趣的朋友可以到這里查看鞋仍。

type Equal<X, Y> =
  (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
    ? true
    : false;

其他

還有五道 easy 題,我在之前《內(nèi)置工具》相關(guān)的篇章里系統(tǒng)講過(guò)了搅吁,這里就不占篇幅了威创。大家有興趣的話可以回顧一下本系列先前的文章。

《ts 類型體操-內(nèi)置工具(上)》

《ts 類型體操-內(nèi)置工具(中)》

《ts 類型體操-內(nèi)置工具(下)》

小結(jié)

Easy 篇主要還是在介紹語(yǔ)法谎懦,這些語(yǔ)法非常實(shí)用肚豺,是以后 medium 題目的基礎(chǔ)〗缋梗可以肯定的是吸申,不做題的同學(xué)基本不可能了解這類知識(shí)。類型系統(tǒng)是一門圖靈完備的語(yǔ)言,但是我很想吐槽 ts 官方文檔截碴,它把很重要的語(yǔ)法點(diǎn)散落在在邊邊角角的篇章里梳侨,以至于普通人根本意識(shí)不到它的語(yǔ)言能力。也許正是因?yàn)楣俜降牟恢匾暼盏ぃ瑢?dǎo)致絕大多數(shù)同學(xué)的 ts 水平永遠(yuǎn)停留在了新手村走哺。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市哲虾,隨后出現(xiàn)的幾起案子丙躏,更是在濱河造成了極大的恐慌,老刑警劉巖束凑,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晒旅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡湘今,警方通過(guò)查閱死者的電腦和手機(jī)敢朱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)摩瞎,“玉大人,你說(shuō)我怎么就攤上這事孝常∑烀牵” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵构灸,是天一觀的道長(zhǎng)上渴。 經(jīng)常有香客問(wèn)我,道長(zhǎng)喜颁,這世上最難降的妖魔是什么稠氮? 我笑而不...
    開(kāi)封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮半开,結(jié)果婚禮上隔披,老公的妹妹穿的比我還像新娘。我一直安慰自己寂拆,他們只是感情好奢米,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著纠永,像睡著了一般鬓长。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上尝江,一...
    開(kāi)封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天涉波,我揣著相機(jī)與錄音,去河邊找鬼。 笑死啤覆,一個(gè)胖子當(dāng)著我的面吹牛苍日,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播城侧,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼易遣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了嫌佑?” 一聲冷哼從身側(cè)響起豆茫,我...
    開(kāi)封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎屋摇,沒(méi)想到半個(gè)月后揩魂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡炮温,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年火脉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柒啤。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡倦挂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出担巩,到底是詐尸還是另有隱情方援,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布涛癌,位于F島的核電站犯戏,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拳话。R本人自食惡果不足惜先匪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望弃衍。 院中可真熱鬧呀非,春花似錦、人聲如沸笨鸡。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)形耗。三九已至哥桥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間激涤,已是汗流浹背拟糕。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工判呕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人送滞。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓侠草,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親犁嗅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子边涕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 本文是 ts 內(nèi)置工具最后一篇赦邻。拖拖拉拉總算要把所有的內(nèi)置工具講完了侵蒙。 NonNullable<Type>:從類型...
    anOnion閱讀 91評(píng)論 0 1
  • 在 TypeScript 中示绊,內(nèi)置工具類型(utility types)是一組預(yù)定義的類型蚀瘸,用于在類型層面上進(jìn)行各...
    anOnion閱讀 253評(píng)論 0 1
  • 如今,絕大多數(shù)前端開(kāi)發(fā)者現(xiàn)在都已經(jīng)接觸過(guò) Typescript檬寂。在和同僚一起學(xué)習(xí)的過(guò)程中宪潮,我發(fā)現(xiàn)他們雖然在使用 T...
    anOnion閱讀 427評(píng)論 0 0
  • 逆變與協(xié)變是泛型類型中的一個(gè)概念告匠,當(dāng)然不只只是 TS 獨(dú)有的概念求厕。簡(jiǎn)單來(lái)說(shuō)著隆,假設(shè)存在類型 T2 為 T1 的子類,...
    l1n3x閱讀 2,293評(píng)論 1 3
  • 書接上文呀癣。在上一節(jié)中美浦,我們學(xué)習(xí)了 8 個(gè)最常用的內(nèi)置工具類型。這些工具類型都是對(duì)現(xiàn)有類型進(jìn)行“變形”的工具项栏,它們可...
    anOnion閱讀 132評(píng)論 0 1