Implement a generic
Last<T>that takes an Array T and returns its last element.
實作一個泛型 Last<T>,它接受一個陣列 T,並返回其最後一個元素。
type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1]
type tail1 = Last<arr1> // expected to be 'c'
type tail2 = Last<arr2> // expected to be 1
接下來,你的任務是讓下面的type cases測試通過:
type cases = [
Expect<Equal<Last<[2]>, 2>>,
Expect<Equal<Last<[3, 2, 1]>, 1>>,
Expect<Equal<Last<[() => 123, { a: string }]>, { a: string }>>,
]
從以下幾個方向來思考:
infer 來從泛型中推導型別。... (Spread Syntax) 把陣列分成前面的部分和最後的元素,然後用 infer 來推斷出最後一個元素的型別。T extends [...any, infer L]:這樣的語法可以分割陣列,把最後一個元素取出來並賦值給 L。這個方法無論陣列長度是固定還是可變,都適用。never 來避免錯誤。解法1:
type Last<T extends any[]> = T extends [...any, infer L] ? L : never
// 也可以改使用 _
type Last<T extends any[]> = T extends [...infer _, infer L] ? L : never
細節分析:
條件型別 (Conditional Types):條件型別允許根據不同的型別來執行不同的邏輯。在這裡,T extends [...any, infer L] 用於檢查 T 是否符合「一個陣列,且最後一個元素可以推斷為 L」的條件。
T extends [...any, infer L] 表示 T 是一個包含任意數量元素的陣列,並且最後一個元素會被推斷為 L。L,否則返回 never。型別推斷 (Type Inference):使用 infer 來從 T 中推斷最後一個元素的型別並將它賦值給 L。這是 TypeScript 在處理陣列或元組中元素時常用的技巧,特別是當我們不知道具體的長度時。
infer L 會嘗試推斷出陣列的最後一個元素的型別,這就是我們想要的結果。省略元素 (Omitting Elements):在 T extends [...infer _, infer L] 中,...infer _ 用來忽略陣列中的其他元素,只關注最後一個元素 L。這表示我們不需要具體知道前面有多少元素,只需要知道最後一個元素是什麼。
_ 在 TypeScript 中通常表示「不需要的型別」或「無關緊要的型別」,所以我們使用 ...infer _ 來跳過前面的所有元素。解法2 (花式):
type Last<T extends any[]> = [never, ...T][T['length']]
細節分析:
型別操作 (Type Manipulation)
T 前面加上 never,這樣可以在訪問 T['length'] 時得到陣列的最後一個元素。T['length'] 會返回陣列 T 的長度,而這個長度正好是原始陣列最後一個元素的索引。步驟細節:
T 是 [string, number, boolean],長度為 3。[never, ...T] 會生成一個新陣列 [never, string, number, boolean],長度變為 4。[never, string, number, boolean][3],即 T['length'] 的位置,會得到原始 T 的最後一個元素 boolean。never 的作用:
處理空陣列:假設 T 是一個空陣列 [],T['length'] 為 0。此時 [never, ...T] 變成 [never],而 [never][0] 會返回 never。這是一個安全的回應,因為空陣列沒有最後一個元素,因此返回 never 是合理的。
防止索引越界:對於非空陣列,[never, ...T] 確保訪問 T['length'] 的索引是有效的。例如,對於 T = [string, number],T['length'] 是 2,而 [never, string, number][2] 正好返回 number,也就是 T 的最後一個元素。如果沒有 never,T[T['length']] 可能會導致越界訪問錯誤。
這樣,我們就能順利通過測試啦 🎉 😭 🎉
本次介紹了 Last of Array 的實作,下一關會挑戰 Pop,期待再相見!