欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長(zhǎng)資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          最近遇見(jiàn)一道不錯(cuò)的 TS 面試題,分享一下。

          這道題有 3 個(gè)層次,我們一層層來(lái)看。

          第一層的要求是這樣的:

          實(shí)現(xiàn)一個(gè) zip 函數(shù),對(duì)兩個(gè)數(shù)組的元素按順序兩兩合并,比如輸入 [1,2,3], [4,5,6] 時(shí),返回 [[1,4], [2,5],[3,6]]

          這層就是每次各從兩個(gè)數(shù)組取一個(gè)元素,合并之后放到數(shù)組里,然后繼續(xù)處理下一個(gè),遞歸進(jìn)行這個(gè)流程,直到數(shù)組為空即可。

          function zip(target, source) {   if (!target.length || !source.length) return [];    const [one, ...rest1] = target;   const [other, ...rest2] = source;    return [[one, other], ...zip(rest1, rest2)]; }
          登錄后復(fù)制

          結(jié)果是對(duì)的:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          第一層還是比較簡(jiǎn)單的,然后我們來(lái)看第二層要求:

          給這個(gè) zip 函數(shù)定義 ts 類(lèi)型(兩種寫(xiě)法)

          函數(shù)的定義有兩種形式:

          直接通過(guò) function 聲明函數(shù):

          function func() {}
          登錄后復(fù)制

          和聲明匿名函數(shù)然后賦值給變量:

          const func = () => {}
          登錄后復(fù)制

          而參數(shù)和返回值的類(lèi)型都是數(shù)組,只是具體類(lèi)型不知道,可以寫(xiě) unknown[]。

          所以?xún)煞N函數(shù)類(lèi)型的定義就是這樣的:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          也是直接 function 聲明函數(shù)類(lèi)型和 interface 聲明函數(shù)類(lèi)型然后加到變量類(lèi)型上兩種。

          因?yàn)榫唧w元素類(lèi)型不知道,所以用 unknown。

          這里可能會(huì)問(wèn) any 和 unknown 的區(qū)別:

          any 和 unknown 都可以接收任何類(lèi)型:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          但是 any 也可以賦值給任何類(lèi)型,但 unknown 不行。

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          這里只是用來(lái)接收其他類(lèi)型, 所以 unknown 比any 更合適一些,更安全。

          這一層也是比較基礎(chǔ)的 ts 語(yǔ)法,第三層就上了難度了:

          用類(lèi)型編程實(shí)現(xiàn)精確的類(lèi)型提示,比如參數(shù)傳入 [1,2,3], [4,5,6],那返回值的類(lèi)型要提示出 [[1,4], [2,5],[3,6]]

          這里要求返回值類(lèi)型是精確的,我們就要根據(jù)參數(shù)的類(lèi)型來(lái)動(dòng)態(tài)生成返回值類(lèi)型。

          也就是這樣:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          聲明兩個(gè)類(lèi)型參數(shù) Target、Source,約束為 unknown[],也就是元素類(lèi)型任意的數(shù)組類(lèi)型。

          這倆類(lèi)型參數(shù)分別是傳入的兩個(gè)參數(shù)的類(lèi)型。

          返回值通過(guò) Zip 計(jì)算得出。

          然后要實(shí)現(xiàn) Zip 的高級(jí)類(lèi)型:

          傳入的類(lèi)型參數(shù)分別是兩個(gè)數(shù)組類(lèi)型,我們同樣要從中提取出每個(gè)元素合并到一起。

          提取元素可以用模式匹配的方式:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          所以這個(gè)類(lèi)型就可以這樣定義:

          type Zip<One extends unknown[], Other extends unknown[]> =     One extends [infer OneFirst,...infer Rest1]       ? Other extends [infer OtherFirst, ...infer Rest2]         ? [[OneFirst, OtherFirst], ...Zip<Rest1, Rest2>]         : []       : [];
          登錄后復(fù)制

          分別提取兩個(gè)數(shù)組的第一個(gè)元素,構(gòu)造成新數(shù)組。然后對(duì)剩下的數(shù)組遞歸進(jìn)行這樣的處理,直到數(shù)組為空。

          這樣就實(shí)現(xiàn)了我們想要的高級(jí)類(lèi)型:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          但你把它作為返回值加到函數(shù)上會(huì)報(bào)錯(cuò):

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          因?yàn)槁暶骱瘮?shù)的時(shí)候都不知道參數(shù)是啥,自然計(jì)算不出 Zip<Target, Source> 的值,所以這里會(huì)類(lèi)型不匹配:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          那怎么辦呢?

          可以用函數(shù)重載解決:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          ts 支持函數(shù)重載,可以寫(xiě)多個(gè)同名函數(shù)的類(lèi)型的類(lèi)型定義,最后寫(xiě)函數(shù)的實(shí)現(xiàn),這樣用到這個(gè)函數(shù)的時(shí)候會(huì)根據(jù)參數(shù)的類(lèi)型來(lái)匹配函數(shù)類(lèi)型。

          我們用了類(lèi)型編程的那個(gè)函數(shù)通過(guò)這種方式寫(xiě)就不會(huì)報(bào)錯(cuò)了。

          我們使用下看看:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          咋返回值的類(lèi)型不對(duì)呢?

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          其實(shí)這時(shí)候匹配的函數(shù)類(lèi)型是對(duì)的,只不過(guò)推導(dǎo)出的不是字面量類(lèi)型。

          這時(shí)候可以加個(gè) as const。

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          但是加上 as const 會(huì)推導(dǎo)出 readonly [1,2,3]

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          這樣類(lèi)型就不匹配了,所以要在類(lèi)型參數(shù)的聲明上也加上 readonly:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          但這樣 Zip 函數(shù)的類(lèi)型又不匹配了。

          難道要把所有用到這個(gè)類(lèi)型的地方都加上 readonly 么?

          不用,我們 readonly 的修飾去掉不就行了?

          Typescript 有內(nèi)置的高級(jí)類(lèi)型 readonly:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          可以把索引類(lèi)型的每個(gè)索引都加上 readonly 修飾:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          但沒(méi)有提供去掉 readonly 修飾的高級(jí)類(lèi)型,我們可以自己實(shí)現(xiàn)一下:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          用映射類(lèi)型的語(yǔ)法構(gòu)造個(gè)新索引類(lèi)型,加上個(gè) -readonly 就是去掉 readonly 修飾的意思。

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          有的同學(xué)可能問(wèn)了,數(shù)組類(lèi)型也是索引類(lèi)型么?

          是,索引類(lèi)型是聚合多個(gè)元素的類(lèi)型,所以對(duì)象、數(shù)組、class 都是。

          所以我們把它用在數(shù)組上自然也是可以的:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          (準(zhǔn)確來(lái)說(shuō)叫元組,元組是元素個(gè)數(shù)固定的數(shù)組)

          那我們只要在傳入 Zip 之前,用 Mutable 去掉 readonly 就可以了:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          再來(lái)試一下:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          大功告成!現(xiàn)在返回值的類(lèi)型就對(duì)了。

          但還有個(gè)問(wèn)題,如果不是直接傳入字面量,是推導(dǎo)不出字面量類(lèi)型的,這時(shí)候貌似就不對(duì)了:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          可我們不都聲明重載類(lèi)型了么?

          如果推導(dǎo)不出字面量類(lèi)型,應(yīng)該匹配這個(gè)呀:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          但實(shí)際上它匹配的還是第一個(gè):

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          這時(shí)候其實(shí)只要調(diào)換下兩個(gè)函數(shù)類(lèi)型的順序就可以了:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          這時(shí)字面量參數(shù)的情況依然也是對(duì)的:

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          為什么呢?

          因?yàn)?strong>重載函數(shù)的類(lèi)型是從上到下依次匹配,只要匹配到一個(gè)就應(yīng)用。

          非字面量的情況,類(lèi)型是 number[],能匹配 unknown[] 的那個(gè)類(lèi)型,所以那個(gè)函數(shù)類(lèi)型生效了。

          分享一道不錯(cuò)的TS面試題(含3層),看看能答到第幾層!

          而字面量的情況,推導(dǎo)出的是 readonly [1,2,3],帶有 readonly 所以不匹配 unknown[],繼續(xù)往下匹配,就匹配到了帶有類(lèi)型參數(shù)的那個(gè)函數(shù)類(lèi)型。

          這樣兩種情況就都應(yīng)用了合適的函數(shù)類(lèi)型。

          全部代碼是這樣的:

          type Zip<One extends unknown[], Other extends unknown[]> = One extends [   infer OneFirst,   ...infer Rest1 ]   ? Other extends [infer OtherFirst, ...infer Rest2]     ? [[OneFirst, OtherFirst], ...Zip<Rest1, Rest2>]     : []   : [];  type Mutable<Obj> = {   -readonly [Key in keyof Obj]: Obj[Key]; };  function zip(target: unknown[], source: unknown[]): unknown[];  function zip<Target extends readonly unknown[], Source extends readonly unknown[]>(   target: Target,   source: Source ): Zip<Mutable<Target>, Mutable<Source>>;  function zip(target: unknown[], source: unknown[]) {   if (!target.length || !source.length) return [];    const [one, ...rest1] = target;   const [other, ...rest2] = source;    return [[one, other], ...zip(rest1, rest2)]; }  const result = zip([1, 2, 3] as const, [4, 5, 6] as const);  const arr1 = [1, 2, 3]; const arr2 = [4, '5', 6];  const result2 = zip(arr1, arr2);
          登錄后復(fù)制

          ts playground 地址

          總結(jié)

          今天我們做了一道綜合的 ts 面試題,一共有三層:

          第一層實(shí)現(xiàn) js 的邏輯,用遞歸或者循環(huán)都能實(shí)現(xiàn)。

          第二層給函數(shù)加上類(lèi)型,用 function 聲明類(lèi)型和 interface 聲明函數(shù)類(lèi)型兩種方式,參數(shù)和返回值都是 unknown[]。

          第三層是用類(lèi)型編程實(shí)現(xiàn)精準(zhǔn)的類(lèi)型提示,這一層需要拿到參數(shù)的類(lèi)型,通過(guò)提取元素的類(lèi)型并構(gòu)造出新的數(shù)組類(lèi)型返回。還要通過(guò)函數(shù)重載的方式來(lái)聲明類(lèi)型,并且要注意重載類(lèi)型的聲明順序。

          as const 能夠讓字面量推導(dǎo)出字面量類(lèi)型,但會(huì)帶有 readonly 修飾,可以自己寫(xiě)映射類(lèi)型來(lái)去掉這個(gè)修飾。

          其實(shí)這也是我們學(xué)習(xí) ts 的順序,我們先要能把 js 邏輯寫(xiě)出來(lái),然后知道怎么給函數(shù)、class 等加 ts 類(lèi)型,之后學(xué)習(xí)類(lèi)型編程,知道怎么動(dòng)態(tài)生成類(lèi)型。

          其中類(lèi)型編程是 ts 最難的部分,也是最強(qiáng)大的部分。攻克了這一層,ts 就可以說(shuō)學(xué)的差不多了。

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)