TypeScript 中每个键的泛型映射对象类型

Posted

技术标签:

【中文标题】TypeScript 中每个键的泛型映射对象类型【英文标题】:Mapped object type with generic per key in TypeScript 【发布时间】:2021-03-28 07:36:17 【问题描述】:

假设我有一个类型,它是由两项组成的任意数组:参数列表和参数与参数匹配的函数。为了方便起见,我创建了一个可以推断泛型类型的函数。

type MapParamsToFunction<A extends any[]> = [[...params: A], (...args: A) => void]

function asMap<A extends any[]>(map: MapParamsToFunction<A>): MapParamsToFunction<A> 
    return map;


asMap([[],() => ]) // good
asMap([[0, "Hello World", 2], (a: number, b: string, c: number) =>  ]); // good
asMap([[0, "Hello World", 2], (a: number, b: number, c: number) =>  ]); // error
asMap([[0, "Hello World"], (a: number, b: string, c: number) =>  ]); // error

目前没有问题。现在,我想使用它并创建一个字典,其中每个键可以有不同的参数/参数列表。但是,我看不到让 TypeScript 在每个键上使用不同泛型的方法。

我尝试在类型上使用any[],但如果参数与参数不匹配,它不会引发类型错误。

type FunctionDictionary<T extends string> = 
    [K in T]: MapParamsToFunction<any[]>


function asDictionary<T extends string>(dict: FunctionDictionary<T>): FunctionDictionary<T> 
    return dict;


let obj = asDictionary(
    "foo": [[0, "Hello World", 2], (a: number, b: number, c: number) =>  ], // no type error
    "bar": [["","",""], (a: string, b: string, c: string) =>  ]
);

有没有办法映射这个,所以每个参数都可以有它自己的通用参数列表?

type FunctionDictionary<T extends string> = 
    [K in T]: MapParamsToFunction<?> // <--- what goes here

【问题讨论】:

【参考方案1】:

TypeScript 没有 existential types 来表示“a MapParamsToFunction&lt;X&gt; for some type X”,因此您不能只将 FunctionDictionary 记录下来。幸运的是,它确实允许 inference from mapped types,因此您可以采用 对象类型 T,其属性都是参数列表,并将每个属性 K 映射到适当的 MapParamsToFunction&lt;T[K]&gt;

type FunctionDictionary<T extends Record<keyof T, any[]>> = 
    [K in keyof T]: MapParamsToFunction<T[K]>

然后您的asDictionary() 将从传入的FunctionDictionary&lt;T&gt; 中推断出T 对象,如下所示:

function asDictionary<T extends Record<keyof T, any[]>>(
    dict: FunctionDictionary<T>
): FunctionDictionary<T> 
    return dict;

你得到你想要的行为:

let obj = asDictionary(
    "foo": [[0, "Hello World", 2], (a: number, b: number, c: number) =>  ], // error!
    // --------------------------> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Types of parameters 'b' and 'args_1' are incompatible.
    "bar": [["", "", ""], (a: string, b: string, c: string) =>  ]
);

Playground link to code

【讨论】:

您在此处的回答帮助我弄清楚了如何解决一个不同但相关的问题,该问题围绕参数化 api 对象,其中键是方法名称,值是提取器函数,如 (p: Params) =&gt; Promise&lt;Response&gt;。显示T 可以在T extends Record&lt;keyof T, any[]&gt; 中引用自身的示例特别有用。谢谢! twitter.com/davidcrespo/status/1380555171130920961

以上是关于TypeScript 中每个键的泛型映射对象类型的主要内容,如果未能解决你的问题,请参考以下文章

如何使用带有 Typescript 的泛型将中继(graphql)连接映射到边缘节点

Typescript - 确保泛型属性存在于具有描述性错误的泛型类型上

使用正确的泛型类型迭代对象

TypeScript 中具有泛型类型参数的泛型类型的替代方案

是否可以在 TypeScript 中传播独特的泛型类型?

在 Typescript 的泛型类中初始化泛型类型