類型 - Typescript:根據枚舉成員的數量獲取具有固定長度的元組
假設我有一個列舉型別
enum Chest {
ID,
NAME,
CAPACITY,
OPEN_WIN_POINTS,
}
而我想要建立一個元組,其長度與枚舉中的值數量相同。所以對於上述的例子,我想要一個長度為4的字串元組:
type ChestStringTuple = EnumTuple<string, Chest>
const correctTuple: ChestStringTuple = ['foo', 'bar', 'baz', 'goo']
const incorrectTuple1: ChestStringTuple = ['foo', 'bar', 'baz'] // The number of tuple members differs from 4
const incorrectTuple2: ChestStringTuple = ['foo', 'bar', 'baz', false] // The tuple has non-string members
有沒有辦法取得列舉成員的數量並將其作為元組的長度使用?
答案#1
結合了在 SO 上提出的各種問題的解決方案,我設法創建了一個應該完全符合你需求的解決方法!
首先,讓我們抓取一個可以為我們建立元組的類型吧!
type BuildTuple<Current extends [...T[]], T, Count extends number> =
Current["length"] extends Count
? Current
: BuildTuple<[T, ...Current], T, Count>
type Tuple<T, Count extends number> = BuildTuple<[], T, Count>
然後我們將跳到這個 SO 問題,它有一些非常有用的聯集輔助函數!
type UnionToIntersection<U> =(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
type UnionToOvlds<U> = UnionToIntersection<U extends any ? (f: U) => void : never>;
type PopUnion<U> = UnionToOvlds<U> extends ((a: infer A) => void) ? A : never;
然後我們將會重寫那個 SO 答案中的主要方法,因為我們的目標不是將聯合類型轉換為元組(我不建議這麼做——閱讀這篇文章可以了解原因)。
type UnionCount<U, L extends any[] = []> = {
0: PopUnion<U> extends infer SELF ? UnionCount<Exclude<U, SELF>, [any, ...L]> : never;
1: L['length'];
}[[U] extends [never] ? 1 : 0];
從那裡開始,其餘的就相當簡單了。我們會製作幾個別名類型,以便閱讀更容易
type InterfaceLength<T> = UnionCount<keyof T>;
type EnumLength<T> = UnionCount<T>;
如果我們將所有這些結合在一起,我們就可以創建我們的最終枚舉
type InterfaceTuple<T, L> = Tuple<T, InterfaceLength<L>>;
type EnumTuple<T, L> = Tuple<T, EnumLength<L>>;
您的代碼:
enum Chest {
ID,
NAME,
CAPACITY,
OPEN_WIN_POINTS,
}
type ChestStringTuple = EnumTuple<string, Chest>
const correctTuple: ChestStringTuple = ['foo', 'bar', 'baz', 'goo'] // Valid
const incorrectTuple1: ChestStringTuple = ['foo', 'bar', 'baz'] // Not valid
const incorrectTuple2: ChestStringTuple = ['foo', 'bar', 'baz', false] // Not valid
遊樂場
自行承擔風險使用。
