我目前正处于从JS过渡到TS的过程中,无法完全了解keyof
。我找到了https://github.com/kimamula/TypeScript-definition-of-EventEmitter-with-keyof,现在我正在努力实现这一点。一切顺利,直到我打开'noImplicitAny'。
我在ts操场上制作了example以显示我遇到的问题:
在构造函数中,无法访问K
,因此我必须明确地使地图(arg: any)
能够使其发挥作用。
是否存在避免在创建Map时使用any的解决方案?
答案 0 :(得分:0)
问题是您尝试将(arg: keyof T) => any
分配给(arg: T[K]) => any
。 keyof 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