类似于:
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'
// }
如何使用打字稿来实现?
答案 0 :(得分:3)
可能有一种方法可以优化/折叠这种类型,但我有getProperties
的函数原型,我相信它可以实现你想要的。
定义中缺少的是一个强大的返回类型定义,它将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]]}
它为V
对象中的每个键keys
指定:
V
将成为输出对象中的键
值类型将是输入obj
中的类型,其中类型来自与V
中与键U
关联的值指定的键。
答案 1 :(得分:3)
只要它在运行时工作,就可以告诉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).reduce((result, [key, value]: [keyof KS, any]) => {
result[key] = getProperty(obj, value);
return result;
}, def);
}
这应该在类型系统中按预期运行。要点:keys
的类型被赋予一个名为KS
的类型参数,该参数被约束为Record<keyof KS, keyof T>
,这或多或少意味着&#34;我不在乎什么密钥是,但属性类型需要是T
&#34;的密钥。然后,RenameKeys<T, KS>
遍历KS
的密钥,并从与其相关的T
中提取属性类型。
最后,我需要做一些类型的断言...... def
是RenameKeys<T, KS>
。我刚才value
[key, value]
中any
的类型result[key]
,因为类型系统很难确认getProperties()
是正确的类型。所以它对实现类型的安全性有点捏造......但是const {a2, n2} = getProperties(person, {
a2: 'name',
n2: 'age'
});
// a2 is string|number, n2 is string|number
的调用者应该感到高兴:
const {a2, n2} = getProperties(person, {
a2: 'name' as 'name',
n2: 'age' as 'age',
});
// a2 is string, n2 is number.
等等,什么?哦,那是因为TypeScript doesn't narrow properties to string/numeric literals automatically。解决方法是明确断言缩小类型,以避免不幸的重复:
{{1}}
希望有所帮助!