【问题标题】:How to return an object where keys are inferred from input object?如何返回从输入对象推断出键的对象?
【发布时间】:2019-08-01 14:09:03
【问题描述】:

我想在 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 抱怨不能使用类型 string索引给定的对象类型。对此有何提示?

【问题讨论】:

    标签: javascript typescript type-inference


    【解决方案1】:

    你可以解决这个问题

    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.

    【讨论】:

      【解决方案2】:

      {[ 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 };
      }
      

      【讨论】:

        猜你喜欢
        • 2021-04-24
        • 2019-08-12
        • 2020-06-22
        • 1970-01-01
        • 2014-12-10
        • 1970-01-01
        • 2020-08-22
        • 2020-08-14
        • 1970-01-01
        相关资源
        最近更新 更多