iT邦幫忙

2024 iThome 鐵人賽

DAY 29
0
JavaScript

TypeScript Type Challenges 冒險篇章:30 天闖關之旅,type 簡單了?你確定?系列 第 29

第29關:Flatten!TypeScript 軍中情人:你問我愛你有多深~陣列有幾層?

  • 分享至 

  • xImage
  •  

第29關:Flatten

關卡簡介

In this challenge, you would need to write a type that takes an array and emitted the flatten array type.

在這個挑戰中,你需要編寫一個類型,接收一個陣列並輸出扁平化後的陣列類型。

任務說明:

type flatten = Flatten<[1, 2, [3, 4], [[[5]]]]> // [1, 2, 3, 4, 5]

你的任務是讓下面的type cases測試通過:

type cases = [
  Expect<Equal<Flatten<[]>, []>>,
  Expect<Equal<Flatten<[1, 2, 3, 4]>, [1, 2, 3, 4]>>,
  Expect<Equal<Flatten<[1, [2]]>, [1, 2]>>,
  Expect<Equal<Flatten<[1, 2, [3, 4], [[[5]]]]>, [1, 2, 3, 4, 5]>>,
  Expect<Equal<Flatten<[{ foo: 'bar', 2: 10 }, 'foobar']>, [{ foo: 'bar', 2: 10 }, 'foobar']>>,
]

// @ts-expect-error
type error = Flatten<'1'>

冒險指南:

從以下幾個方向來思考:

  • 遞迴解法(Recursive Approach): 透過遞迴,我們可以逐層解析嵌套的陣列,並將內層的元素一層一層地取出並組合起來。每次判斷陣列的首元素是否還是陣列,如果是,繼續展開;如果不是,將其加入結果。

  • 陣列操作(Array Operations): 我們需要通過類型擴展運算符 (...) 來將陣列中的元素展開,並使用條件類型來遞迴處理剩餘的陣列,直到所有元素都被展開。

通關方式:

解法:

type Flatten<T extends any[], K extends any[] = []> =
  T extends [infer F, ...infer R]
  ? F extends any[]
    ? Flatten<[...F, ...R], K>
    : Flatten<[...R], [...K, F]>
  : K

細節分析:

  • 類型定義 (Type Definition):

    Flatten<T extends any[], K extends any[] = []>

    T 代表我們要處理的嵌套陣列類型,並且要求 T 必須是一個陣列 (T extends any[])。這樣可以確保只對陣列進行扁平化處理。
    K 是用來存放結果的累積陣列,默認情況下初始化為空陣列 (K = []),用於遞迴過程中逐步累加扁平化的結果。

  • 條件類型與遞迴 (Conditional Types and Recursion):

    T extends [infer F, ...infer R]

    這裡使用了 TypeScript 的條件類型和推斷 (infer),來判斷 T 是否為一個非空陣列。如果 T 是一個非空陣列,它將被分解為兩部分:F 表示陣列的第一個元素,R 表示剩餘的元素。
    如果 T 是空陣列(即已遞迴處理到陣列的末尾),條件類型將自動跳到 K,並返回最終的累積結果。

    F extends any[]

    判斷 F 是否為一個陣列,如果是的話,我們需要繼續扁平化這個陣列。因此,透過運算符 ...FR 展開為單一陣列,並遞迴處理該新陣列。這樣可以確保 F 的內部元素也被展開並逐步處理。

  • 累積結果 (Accumulate Result):

    Flatten<R, [...K, F]>

    F 不是一個陣列時(即 F 是一個基本類型或物件等),我們將其添加到累積結果陣列 K 中。
    使用展開運算符 [...]KF 拼接起來,生成新的累積結果。
    然後,對剩餘的元素 R 進行遞迴處理,直到陣列 T 被完全處理為止。

  • 基礎情況(終止條件)(Base Case - Termination Condition):

    當陣列 T 為空時,即遞迴過程結束,表示我們已經處理完所有元素。在這種情況下,遞迴停止,並返回最終的累積結果 K

額外補充:
https://ithelp.ithome.com.tw/upload/images/20241013/20168789E9xZ3Q7TYq.png
https://ithelp.ithome.com.tw/upload/images/20241013/20168789E3Pa45SMX4.pnghttps://ithelp.ithome.com.tw/upload/images/20241013/20168789MS0AWTBV2r.png

這樣,我們就能順利通過測試啦 🎉 😭 🎉

總結:

本次介紹了Flatten 的實作,下一關會挑戰 Append to object,期待再相見!


上一篇
第28關:Length of String!TypeScript 司馬遷,字"子長":字串有多長?
下一篇
第30關:Special Edition - Endgame:FP & GMT
系列文
TypeScript Type Challenges 冒險篇章:30 天闖關之旅,type 簡單了?你確定?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言