For given a tuple, you need create a generic
Length, pick the length of the tuple
給定一個元組,實現一個泛型 Length,用來提取該元組的長度。
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
接下來,你的任務是讓下面的type cases測試通過:
const tesla = ['tesla', 'model 3', 'model X', 'model Y'] as const
const spaceX = ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT'] as const
type cases = [
Expect<Equal<Length<typeof tesla>, 4>>,
Expect<Equal<Length<typeof spaceX>, 5>>,
]
在這一關中,我們可以從以下幾個方向來思考:
T 是一個 tuple ?我們將會用到:
readonly 關鍵字確保元組的元素是不可變的,即它的內容無法被修改。在這裡使用 readonly 是為了更準確地確保 T 是一個 tuple (元組),而不是普通的陣列extends 在第三關已經介紹過,可以回到第三關參考喔!
在開始之前,讓我們先來看看如何定義和處理 tuple / array。

使用 as const 將 tesla 定義為 readonly ["tesla", "model 3", "model X", "model Y"],這意味著這是一個 readonly tuple 只讀元組。這樣的定義使得元組的每個元素和長度都是固定的,無法被修改。
當我們用 Length2<T extends any[]> 來獲取長度時,會出現錯誤,因為 Length2 要求 T 是可變的數組(any[])。但 tesla 變成了只讀類型,TypeScript 不允許將 readonly 的元組賦值給可變數組。
這個錯誤提示我們 readonly ["tesla", "model 3", "model X", "model Y"] 不能滿足 any[] 的約束,因為它是不可變的。為了解決這個問題,可以將 Length2 的約束改為 readonly any[],這樣就可以正常處理只讀元組,返回元組的長度。
解法1:
type Length<T extends readonly any[]> = T['length']
細節分析:
T extends readonly any[]:這部分確保了 T 是一個只讀的陣列或元組。通過加入 readonly,我們保證 T 的元素是不可變的,這在處理元組時尤為重要,因為元組是固定長度且元素類型明確的數組。使用 readonly 的原因是它限制了數組或元組的可變性,避免誤將元組視作普通的可變數組。
readonly:元組的特性在於它的固定長度和不變的元素類型。readonly 可以進一步加強這個特性,確保編譯器理解我們正在處理的是元組而非普通陣列。這樣做還能防止數組內容被修改,保證類型推斷的精確性。普通陣列的長度和元素類型都可以變動,而我們需要一個穩定、不可變的結構來確保正確的類型操作。any[]:這個語法代表一個可以包含任何類型的陣列或元組。通過這樣的約束,我們確保泛型 T 必須是符合這個形狀的,也就是說,T 必須是一個陣列或元組,不允許傳入非陣列的類型。T['length']:這是 TypeScript 中的一種索引類型語法,它允許我們直接訪問元組或陣列的 length 屬性。每個元組和陣列在 TypeScript 中都有一個內建的 length 屬性,用來表示它的長度。在這裡,我們使用 T['length'] 來提取元組 T 的長度。
type arr = [1, 2, 3];
type lengthOfArr = arr['length']; // 3
這樣,我們就能順利通過測試啦 🎉 😭 🎉
本次介紹了 Length of Tuple 的實作,下一關會挑戰 exclude,期待再相見!