我想在TypeScript中创建一个函数,该函数将一个对象作为参数,并返回另一个具有相同键的对象。从用户的POV基本上应该看起来像这样:
const foo = getBar({ baz: 23 });
console.log(foo.baz);
最初,我使用
{[ key: string ]: number }
作为参数的类型,但这是错误的,因为这意味着每个键都必须有一个值(当您尝试访问非键值时,可以在getBar
内部看到该值那里)。这就是为什么我想到了Dictionary
的自定义实现:
type Dictionary<K extends string, T> = {
[key in K]?: T
};
现在函数的定义如下:
const getBar = function
<T extends Dictionary<string, number>>:
Dictionary<string, number> (values: T)
{
// ...
}
现在在函数内部,我想随着时间的推移建立结果,所以我将初始化一个空的对象以随着时间的推移填充它:
const result: Dictionary<string, number> = {};
当我尝试运行此命令时,TypeScript抱怨{}
无法分配给给定类型。我在这里想念什么?
此外,此方法还不能保证(从类型系统的POV出发)返回的字典具有与输入对象完全相同的键。是否可以表达这一点?如果可以,如何表达?
我发现(但引入了另一个问题)的一种解决方法是将返回值描述为:
{[ key in keyof T ]: number }
现在从外部看来似乎可以正常工作,但是在getBar
函数内部无法再向result
对象添加项目,因为那时TypeScript抱怨类型{{1 }}不能用于索引给定的对象类型。有任何提示吗?
答案 0 :(得分:5)
您可以通过以下方式解决问题
const result: Dictionary<string, number> = {};
通过使用Partial
:
const result: Partial<Dictionary<string, number>> = {};
这确实意味着,一旦您将其填满,就需要在返回时在最后声明一个类型断言。
但是我可能会丢失一些东西(不是第一次),但我认为您不需要Dictionary
类型:
function getBar<T>(foo: T): T {
let retval : Partial<T> = {};
// ...fill in retval
return retval as T;
}
现在可以了
const x = getBar({message: "hi"});
x
的类型为{message: string}
。
答案 1 :(得分:0)
{[ key in keyof T ]: number }
是正确的答案。
只有keyof T
可以索引T类型的对象。
例如如果T = { foo: any; baz: null; }
,则keyof T
= 'foo' | 'baz'
如果对TypeScript的抱怨使您不满意,则可以通过以下方式避免它们:
function bar<T>(obj: T) {
let key_A = 'baz' as keyof T;
obj[key_A]; // no error
let key_B = 'baz'; // now the type of key_B is string
obj[key_B]; // cannot access obj with key_B
const key_C = 'baz'; // the type of key_C is 'baz'
obj[key_C]; // no error
const result = {} as any;
Object.keys(obj).forEach(key => {
result[key] = 12345;
});
return result as {[ key in keyof T ]: number };
}