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

And*_*sta 4 typescript typescript-typings

我无法正确地将任意长度元组的第一种类型推断为元组类型,以维护其标签:

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
Run Code Online (Sandbox Code Playgroud)

有任何想法吗? 操场

预期结果:[a: number]

jca*_*alz 6

以下方法适用于您的示例代码:

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]
Run Code Online (Sandbox Code Playgroud)

这个想法是采用元组类型T并从中推断出R与第一个元素之后的所有内容相对应的元组。一旦R修复,我们可以要求编译器分成T两个元组,最后一个是R. 这将返回一个仅包含第一个元素的元组,且标签完好无损。


当然,有些边缘情况是行不通的,比如可选的元组元素,以及元组类型中的剩余元素,包括前导和中间剩余元素

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[]
Run Code Online (Sandbox Code Playgroud)

我不知道有没有一种没有边缘情况的好方法。根据像这样的GitHub 评论,通过类型转换保留元组标签并不能保证在所有情况下都有效,因此部分功能的解决方案可能是最好的。

Playground 代码链接