TypeScript中是否可以Map命名元组成员?

yk9xbfzb  于 2022-12-01  发布在  TypeScript
关注(0)|答案(1)|浏览(98)

在TypeScript中,我们可以使用Tuple类型来创建类型化的命名rest参数。这对于rest参数很有用。

type Params = [myString: string, myNumber: number, mySecondString: string]

const fn = (...args: Params) => null

// Type is (myString: string, myNumber: number, mySecondString: string) => null

当使用Map的元组类型时,有没有什么方法可以达到同样的效果?

type TypeMap = {
    "string": string
    "number": number
}

const inputs = [
    {name: "myString", type: "string"},
    {name: "myNumber", type: "number"},
    {name: "mySecondString", type: "string"},
] as const

type InputToTuple<T extends typeof inputs> = { [P in keyof T]: TypeMap[T[P]["type"]] };

type Params = InputToTuple<typeof inputs>

const fn = (...args: ParamsIWant) => null
// Type is (args_0: string, args_1: number, args_2: string) => null

当Tuple被创建为Map类型时,是否有方法提供这些参数的 names
核心就是要搞这一行:

type InputToTuple<T extends typeof inputs> = { [P in keyof T]: TypeMap[T[P]["type"]] };

产生此结果:

type Params = InputToTuple<typeof inputs>
// Type is [myString: string, myNumber: number, mySecondString: string]

这可能吗?
Playground
原因说明:我正在构建一种方法,让TypeScript基于Ethereum JSON ABI推断类型(并使用as const进行类型收缩)。

x7rlezfr

x7rlezfr1#

对于问题“TypeScript中是否可能存在Map的命名元组成员?”,答案是“是”,使用元组rest语法。
其思想是分别操作标签和值。
在您的情况下,还有一个额外的约束,即事先不知道标签。这是不可能的,您必须建立一个所有可能标签的列表。

type Labels = {
    myBool: [myBool: unknown],
    myString: [myString: unknown],
    myNumber: [myNumber: unknown],
    mySecondString: [mySecondString: unknown]
};

type TypeMap = {
    "string": string
    "number": number
}

const inputs = [
    {name: "myString", type: "string"},
    {name: "myNumber", type: "number"},
    {name: "mySecondString", type: "string"},
] as const

type Result = GetTupleFromInput<Labels, TypeMap, typeof inputs>;
// Result: [myString: string, myNumber: number, mySecondString: string];

运动场
奇迹就发生在这里

// We stitch together the tuple template
type TemplateFromInput<
    Labels extends {[k: string]: [unknown]},
    Input extends readonly { name: keyof Labels }[],
    I extends number = 0,
    R extends unknown[] = []
> = I extends Input['length'] ? R
    : TemplateFromInput<Labels, Input, Next<I>, [...R, ...Labels[Input[I]['name']]]>

type Next<I extends number> = [1,2,3,4,5,6,7,8,9][I];

// We extract the values / I generalised InputToTuple
type ValuesFromInput<T, TypeMap> = {
    [P in keyof T]:
        T[P] extends { type: keyof TypeMap }
        ? TypeMap[T[P]["type"]] : T[P]
};

// We inject the values back in the template
type GetTupleFromInput<
    Labels extends {[k: string]: [unknown]},
    TypeMap extends {[k: string]: unknown},
    Input extends readonly { type: keyof TypeMap, name: keyof Labels }[],
    Template extends unknown[] = TemplateFromInput<Labels, Input>,
    Values = ValuesFromInput<Input, TypeMap>
> = {[K in keyof Template]: Values[K & keyof Values]};

相关问题