如何将元组的第一个元素推断为元组类型

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>>;

Playground

等待是否有人知道 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 评论,不能保证通过类型转换保留元组标签在所有情况下都有效,因此部分功能的解决方案可能会尽可能好。

Playground link to code