如何返回从输入对象推断出键的对象?

时间:2019-08-01 14:09:03

标签: javascript typescript type-inference

我想在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 }}不能用于索引给定的对象类型。有任何提示吗?

2 个答案:

答案 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}

On the playground

答案 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 };
}
相关问题