站長資訊網
        最全最豐富的資訊網站

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

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

        最近遇見一道不錯的 TS 面試題,分享一下。

        這道題有 3 個層次,我們一層層來看。

        第一層的要求是這樣的:

        實現一個 zip 函數,對兩個數組的元素按順序兩兩合并,比如輸入 [1,2,3], [4,5,6] 時,返回 [[1,4], [2,5],[3,6]]

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

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

        結果是對的:

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

        第一層還是比較簡單的,然后我們來看第二層要求:

        給這個 zip 函數定義 ts 類型(兩種寫法)

        函數的定義有兩種形式:

        直接通過 function 聲明函數:

        function func() {}
        登錄后復制

        和聲明匿名函數然后賦值給變量:

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

        而參數和返回值的類型都是數組,只是具體類型不知道,可以寫 unknown[]。

        所以兩種函數類型的定義就是這樣的:

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

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

        也是直接 function 聲明函數類型和 interface 聲明函數類型然后加到變量類型上兩種。

        因為具體元素類型不知道,所以用 unknown。

        這里可能會問 any 和 unknown 的區別:

        any 和 unknown 都可以接收任何類型:

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

        但是 any 也可以賦值給任何類型,但 unknown 不行。

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

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

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

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

        用類型編程實現精確的類型提示,比如參數傳入 [1,2,3], [4,5,6],那返回值的類型要提示出 [[1,4], [2,5],[3,6]]

        這里要求返回值類型是精確的,我們就要根據參數的類型來動態生成返回值類型。

        也就是這樣:

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

        聲明兩個類型參數 Target、Source,約束為 unknown[],也就是元素類型任意的數組類型。

        這倆類型參數分別是傳入的兩個參數的類型。

        返回值通過 Zip 計算得出。

        然后要實現 Zip 的高級類型:

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

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

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

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

        所以這個類型就可以這樣定義:

        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>]         : []       : [];
        登錄后復制

        分別提取兩個數組的第一個元素,構造成新數組。然后對剩下的數組遞歸進行這樣的處理,直到數組為空。

        這樣就實現了我們想要的高級類型:

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

        但你把它作為返回值加到函數上會報錯:

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

        因為聲明函數的時候都不知道參數是啥,自然計算不出 Zip<Target, Source> 的值,所以這里會類型不匹配:

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

        那怎么辦呢?

        可以用函數重載解決:

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

        ts 支持函數重載,可以寫多個同名函數的類型的類型定義,最后寫函數的實現,這樣用到這個函數的時候會根據參數的類型來匹配函數類型。

        我們用了類型編程的那個函數通過這種方式寫就不會報錯了。

        我們使用下看看:

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

        咋返回值的類型不對呢?

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

        其實這時候匹配的函數類型是對的,只不過推導出的不是字面量類型。

        這時候可以加個 as const。

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

        但是加上 as const 會推導出 readonly [1,2,3]

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

        這樣類型就不匹配了,所以要在類型參數的聲明上也加上 readonly:

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

        但這樣 Zip 函數的類型又不匹配了。

        難道要把所有用到這個類型的地方都加上 readonly 么?

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

        Typescript 有內置的高級類型 readonly:

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

        可以把索引類型的每個索引都加上 readonly 修飾:

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

        但沒有提供去掉 readonly 修飾的高級類型,我們可以自己實現一下:

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

        用映射類型的語法構造個新索引類型,加上個 -readonly 就是去掉 readonly 修飾的意思。

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

        有的同學可能問了,數組類型也是索引類型么?

        是,索引類型是聚合多個元素的類型,所以對象、數組、class 都是。

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

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

        (準確來說叫元組,元組是元素個數固定的數組)

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

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

        再來試一下:

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

        大功告成!現在返回值的類型就對了。

        但還有個問題,如果不是直接傳入字面量,是推導不出字面量類型的,這時候貌似就不對了:

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

        可我們不都聲明重載類型了么?

        如果推導不出字面量類型,應該匹配這個呀:

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

        但實際上它匹配的還是第一個:

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

        這時候其實只要調換下兩個函數類型的順序就可以了:

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

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

        這時字面量參數的情況依然也是對的:

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

        為什么呢?

        因為重載函數的類型是從上到下依次匹配,只要匹配到一個就應用。

        非字面量的情況,類型是 number[],能匹配 unknown[] 的那個類型,所以那個函數類型生效了。

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

        而字面量的情況,推導出的是 readonly [1,2,3],帶有 readonly 所以不匹配 unknown[],繼續往下匹配,就匹配到了帶有類型參數的那個函數類型。

        這樣兩種情況就都應用了合適的函數類型。

        全部代碼是這樣的:

        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);
        登錄后復制

        ts playground 地址

        總結

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

        第一層實現 js 的邏輯,用遞歸或者循環都能實現。

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

        第三層是用類型編程實現精準的類型提示,這一層需要拿到參數的類型,通過提取元素的類型并構造出新的數組類型返回。還要通過函數重載的方式來聲明類型,并且要注意重載類型的聲明順序。

        as const 能夠讓字面量推導出字面量類型,但會帶有 readonly 修飾,可以自己寫映射類型來去掉這個修飾。

        其實這也是我們學習 ts 的順序,我們先要能把 js 邏輯寫出來,然后知道怎么給函數、class 等加 ts 類型,之后學習類型編程,知道怎么動態生成類型。

        其中類型編程是 ts 最難的部分,也是最強大的部分。攻克了這一層,ts 就可以說學的差不多了。

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 久久久久久九九99精品| 国产精品视频分类一区| 91精品国产9l久久久久| 久久激情亚洲精品无码?V| 精品福利一区二区三| 日韩精品系列产品| 日韩精品无码久久一区二区三| 精品国产自在在线在线观看| 久久精品国产亚洲av麻豆色欲| 亚洲国产精品无码久久九九| 国产精品日韩深夜福利久久| 国产精品久久久久无码av| 人妻AV一区二区三区精品| 亚洲AV永久无码精品一区二区 | 亚洲精品无码av人在线观看| 精品一区二区三区免费观看| 国产精品白丝AV嫩草影院| 精品视频在线v| 国产福利微拍精品一区二区| 国产欧美亚洲精品A| 日韩精品视频一区二区三区| 一本一道精品欧美中文字幕| 亚洲精品专区在线观看| 亚洲精品第一国产综合精品99| 蜜臀精品无码AV在线播放| 精品熟女少妇aⅴ免费久久| 国产精品va久久久久久久| 99久久精品国产一区二区三区| 五月花精品视频在线观看| 精品久久777| 欧美日韩精品乱国产538| 精品一区二区三区中文字幕| 欧美精品天天操| 色综合久久精品中文字幕首页| 欧美精品国产精品| 9re热国产这里只有精品| www亚洲欲色成人久久精品| 国产精品一区二区久久精品无码| 国产线视频精品免费观看视频| 精品乱码久久久久久夜夜嗨| 牛牛在线精品观看免费正|