如何将元组的第一个元素推断为元组类型
How to infer first element of a tuple as a tuple type
我无法正确地将任意长度的元组的第一种类型推断为元组类型,以维护其标签:
type First1<T extends any[]> = T extends [infer FIRST, ...any[]] ? FIRST : never
type test1 = First1<[a: number, b: boolean, c: string]> // number
type First2<T extends any[]> = T extends [infer FIRST, ...any[]] ? [FIRST] : never
type test2 = First2<[a: number, b: boolean, c: string]> // [number] <-- obv no label
type First3<T extends any[]> = T extends [...infer FIRST, any, ...any[]] ? FIRST : never
type test3 = First3<[a: number, b: boolean, c: string]> // unknown[] <-- I tried ahah
有什么想法吗?
Playground
预期结果:[a: number]
我目前的解决方案:
type Init<T extends any[]> = T extends [...infer INIT, any] ? INIT : never;
type FirstAsTuple<T extends any[]> = T extends [any]
? T extends [...infer F]
? F
: never
: FirstAsTuple<Init<T>>;
等待是否有人知道 non-recursive 技巧。
以下方法适用于您的示例代码:
type First<T extends any[]> = T extends [any, ...infer R] ?
T extends [...infer F, ...R] ? F : never : never
type Test = First<[a: number, b: boolean, c: string]>
// type Test = [a: number]
想法是采用元组类型 T
并从中推断出对应于第一个元素之后的所有内容的元组 R
。一旦 R
固定,我们可以要求编译器将 T
分成两个元组,最后一个是 R
。 returns 一个只包含第一个元素的元组,标签完好无损。
当然有些极端情况是行不通的,比如optional tuple elements, and rest elements in tuple types including leading and middle rest elements:
type X = First<[a?: number, b?: boolean, c?: string]>; // never
type Y = First<[...a: number[], b: boolean, c: string]> // never
type Z = First<[a: number, ...b: boolean[], c: string]> // unknown[]
我不知道有没有边缘情况的好方法。根据像 this one 这样的 GitHub 评论,不能保证通过类型转换保留元组标签在所有情况下都有效,因此部分功能的解决方案可能会尽可能好。
我无法正确地将任意长度的元组的第一种类型推断为元组类型,以维护其标签:
type First1<T extends any[]> = T extends [infer FIRST, ...any[]] ? FIRST : never
type test1 = First1<[a: number, b: boolean, c: string]> // number
type First2<T extends any[]> = T extends [infer FIRST, ...any[]] ? [FIRST] : never
type test2 = First2<[a: number, b: boolean, c: string]> // [number] <-- obv no label
type First3<T extends any[]> = T extends [...infer FIRST, any, ...any[]] ? FIRST : never
type test3 = First3<[a: number, b: boolean, c: string]> // unknown[] <-- I tried ahah
有什么想法吗? Playground
预期结果:[a: number]
我目前的解决方案:
type Init<T extends any[]> = T extends [...infer INIT, any] ? INIT : never;
type FirstAsTuple<T extends any[]> = T extends [any]
? T extends [...infer F]
? F
: never
: FirstAsTuple<Init<T>>;
等待是否有人知道 non-recursive 技巧。
以下方法适用于您的示例代码:
type First<T extends any[]> = T extends [any, ...infer R] ?
T extends [...infer F, ...R] ? F : never : never
type Test = First<[a: number, b: boolean, c: string]>
// type Test = [a: number]
想法是采用元组类型 T
并从中推断出对应于第一个元素之后的所有内容的元组 R
。一旦 R
固定,我们可以要求编译器将 T
分成两个元组,最后一个是 R
。 returns 一个只包含第一个元素的元组,标签完好无损。
当然有些极端情况是行不通的,比如optional tuple elements, and rest elements in tuple types including leading and middle rest elements:
type X = First<[a?: number, b?: boolean, c?: string]>; // never
type Y = First<[...a: number[], b: boolean, c: string]> // never
type Z = First<[a: number, ...b: boolean[], c: string]> // unknown[]
我不知道有没有边缘情况的好方法。根据像 this one 这样的 GitHub 评论,不能保证通过类型转换保留元组标签在所有情况下都有效,因此部分功能的解决方案可能会尽可能好。