在TypeScript

时间:2017-04-28 07:52:30

标签: typescript mapped-types

如何从对象创建映射类型?如果我尝试以下内容:

interface Stats {
  count: number,
  avg: number
}

class Blah<T> {
  private stats: { [K in keyof T]: Stats };

  constructor(foo: T) {
    this.stats = Object
      .keys(foo)
      .reduce((result, key) => Object.assign(result, { 
        [key]: { count: 0, avg: 1 } 
      }), {});
  }
}

...我收到错误:

  

类型“{}”不能分配给类型'{[K in keyof T]:Stats; }“

这似乎是因为reduce中的初始值与界面不匹配。

我可以将此声明更改为解决方法:

private stats: { [K in keyof T]?: Stats };

...但现在意味着keyof T的某些值可能根据类型未定义。

如果无法在JavaScript中创建没有中间结果的映射对象,如何创建完全映射的类型?

1 个答案:

答案 0 :(得分:1)

这有点单调乏味,但您可以执行以下操作:

interface Stats {
  count: number,
  avg: number
}

type StatsMap<T> = { [K in keyof T]: Stats };

class Blah<T> {
  public stats:StatsMap<T>;

  constructor(foo: T) {
    this.stats = Object
      .keys(foo)
      .reduce<StatsMap<T>>((result, key) => Object.assign(result, { 
        [key]: { count: 0, avg: 1 } 
      }), {} as any);
  }
}

const blah = new Blah({ a: 'a', b: 'b', c: 'c' });
console.log(blah.stats.a.avg); // Yay, no error + autocomplete!

{} as any需要告诉TypeScript您知道自己在做什么: - /

你可以test this on the playground

请注意,我创建了stats memboer public来显示用法!这不是必需的或任何东西。您也不必创建StatsMap,但与多次撰写{ [K in keyof T]: Stats }相比,我觉得更容易阅读。