使用T [K]

时间:2018-01-21 11:09:54

标签: typescript es6-map keyof

我目前正处于从JS过渡到TS的过程中,无法完全了解keyof。我找到了https://github.com/kimamula/TypeScript-definition-of-EventEmitter-with-keyof,现在我正在努力实现这一点。一切顺利,直到我打开'noImplicitAny'。

我在ts操场上制作了example以显示我遇到的问题:

在构造函数中,无法访问K,因此我必须明确地使地图(arg: any)能够使其发挥作用。

是否存在避免在创建Map时使用any的解决方案?

1 个答案:

答案 0 :(得分:0)

问题是您尝试将(arg: keyof T) => any分配给(arg: T[K]) => anykeyof T表示T的任何属性名称。例如,在此类中:

class X { test: string; test2: number; }

keyof X'test' | 'test2'相同 T[K] K extends keyof T T代表名称为K的{​​{1}}属性类型,因此T[K]上面的类可以是number }或string,具体取决于K

传递的值

因此,如果你有Emitter<X>,你基本上会尝试将(arg: string | number) => any分配给(arg: 'test' | 'test2') => any,这绝对不是类型安全的。

我的猜测是你要约束listener使一个参数具有与该类成员相同的属性类型。为此,您应该使用Map<string, ((arg: T[keyof T]) => any) []>arg限制为T

的任何可能属性类型
class EventEmitter<T> {

  private events: Map<string, ((arg: T[keyof T]) => any) []>;

  constructor() {
    this.events = new Map<string, ((arg: T[keyof T]) => any) []>();
  }

  public getOrCreateEvents<K extends keyof T>(event: K, listener: (arg: T[K]) => any): ((arg: T[K]) => any) [] {

    return this.events.get(event) || this.events.set(event, new Array<(arg: T[K]) => any>()).get(event);
  }
}

// Test 
class X { test: string; test2: number; }
var d = new EventEmitter<X>();
d.getOrCreateEvents("test2", c => console.log(c));// c is infered to string
d.getOrCreateEvents("test2", c => console.log(c)); // c is infered to number