元组映射函数类型

tuple mapper function typing

我需要输入一个接受元组并输出它的映射版本的函数
作为第一次尝试,我定义了一个身份元组 returns 一个相同类型的元组

    declare const tupleIdentity: <Tup extends readonly any[]>(tup: Tup) => Tup
    const [a, b, c, d] = tupleIdentity([1, 's', 3]) // a:number, b:string, c:number, d:undefined

太棒了,它跟踪元组的长度和元素类型!
但找不到返回元组映射版本的类型
例如包装每个元素的对象

    // a naive attempt :

    type Wrap<T> = { wrapped: T }
    declare const tupleMapper: <Tup extends readonly any[]>(tup: Tup) 
      => Tup extends Array<infer T> ? Wrap<T>[] : never
    const [x, y, z] = tupleMapper([1, 's', 3]) // x,y,z: Wrap<string | number> | undefined

Ts 类型系统可以声明这样的类型吗?

让我们先稍微改变一下映射器函数:

declare const map: <T extends ReadonlyArray<unknown>>(tuple: T) => MapTuple<T>;

它接受任何元组,然后将该元组传递给一个类型 MapTuple,真正的魔法发生了。

这里是:

type MapTuple<T, R extends ReadonlyArray<unknown> = []> =
    T extends readonly [infer First, ...infer Rest]
        ? MapTuple<Rest, [...R, Wrap<First>]> : R;

我们得到 T 的第一个元素,以及作为另一个元组的其余元素。

如果无法推断出这些,则元组为空,因此我们 return R,结果。

但是,如果是,我们映射剩余的元素,并向结果添加一个包装的第一个元素。

这基本上是一个循环,映射每个元素。

Playground

您可以使用映射类型声明类型(当应用于元组类型时会产生一个元组):

type Wrap<T> = { wrapped: T }

declare const tupleMapper: <Tup extends readonly any[]>(tup: Tup) => 
  {[K in keyof Tup]: Wrap<Tup[K]>}

const [x, y, z] = tupleMapper([1, 's', 3]) // [Wrap<number>, Wrap<string>, Wrap<number>]
// x: Wrap<number>
// y: Wrap<string>
// z: Wrap<number>