如何使用打字稿中的查找来推断类型化的 mapValues?
Posted
技术标签:
【中文标题】如何使用打字稿中的查找来推断类型化的 mapValues?【英文标题】:How to infer typed mapValues using lookups in typescript? 【发布时间】:2018-11-22 04:15:42 【问题描述】:类似于:
How to infer a typed array from a dynamic key array in typescript?
我正在寻找一个通用对象,它接收任意键的映射以查找值,并返回具有类型值的相同键(如类型化 _.mapValues)。
从对象中获取单一类型属性的能力已被记录并有效。对于数组,您需要将重载硬编码为类型化元组,但对于对象,我会收到“重复字符串索引签名”错误。
export interface IPerson
age: number;
name: string;
const person: IPerson =
age: 1,
name: ""
function getProperty<T, K extends keyof T>(o: T, name: K): T[K]
return o[name];
const a = getProperty(person, 'age');
// a: number
const n = getProperty(person, 'name');
// n: string
function getProperties<T, K extends keyof T>(obj: T, keys: [key: string]: K )
const def: [key: string]: T[K] = ;
return Object.entries(keys).reduce((result, [key, value]: [string, K]) =>
result[key] = getProperty(obj, value);
return result;
, def);
const a2, n2 = getProperties(person,
a2: 'name',
n2: 'age'
);
// Result:
//
// a2: string | number,
// n2: string | number
//
// What I'm looking for:
//
// a2: string,
// n2: number'
//
如何使用 typescript 来实现?
【问题讨论】:
抱歉,本想回答您对另一个问题的评论,但忘记了。无论如何@jcalz 也给出了我想的确切答案,不要认为它可以做得更好:-) 【参考方案1】:只要它在运行时工作,您可以告诉 TypeScript 如何使用 mapped types 重命名键:
type RenameKeys<T, KS extends Record<keyof KS, keyof T>> = [K in keyof KS]: T[KS[K]];
function getProperties<T, KS extends Record<keyof KS, keyof T>>(
obj: T,
keys: KS
): RenameKeys<T, KS>
const def = as RenameKeys<T, KS>;
return (Object.entries(keys) as Array<[keyof KS, any]>)
.reduce((result, [key, value]) =>
result[key] = getProperty(obj, value);
return result;
, def);
这应该与您在类型系统中所期望的一样。亮点:keys
的类型被赋予了一个名为KS
的类型参数,它被约束为Record<keyof KS, keyof T>
,这或多或少的意思是“我不在乎键是什么,但属性类型需要是来自T
的密钥”。然后,RenameKeys<T, KS>
遍历KS
的键并从T
中提取与它们相关的属性类型。
最后,我需要做一些类型断言...def
是RenameKeys<T, KS>
。 [key, value]
中value
的类型我刚刚创建了any
,因为类型系统很难验证result[key]
是否是正确的类型。所以这是对实现类型安全性的一种捏造……但getProperties()
的调用者应该很高兴:
const a2, n2 = getProperties(person,
a2: 'name',
n2: 'age'
);
// a2 is string, n2 is number.
Playground link to code
【讨论】:
【参考方案2】:可能有一种方法可以稍微优化/折叠这种输入,但我有一个 getProperties
的函数原型,我相信它可以实现您所寻找的。p>
您的定义中缺少的是一个强大的返回类型定义,它将keys
对象中的特定键与obj
对象中的特定类型之间的关联联系起来。因为缺少了这一点,所以一切都变成了类型的联合,这就是您在上面看到的行为。
我想出的函数类型是:
function getProperties
<T, K extends keyof T, U extends [name: string]: K >
(obj: T, keys: U):
[V in keyof U]: T[U[V]];
这里重要的部分是返回值类型:[V in keyof U]: T[U[V]]
它指定对于keys
对象中的每个键V
:
V
将是输出对象中的一个键
值类型将是来自输入obj
的类型,其中类型来自与U
中的键V
关联的值给出的键。
【讨论】:
以上是关于如何使用打字稿中的查找来推断类型化的 mapValues?的主要内容,如果未能解决你的问题,请参考以下文章