The problem is that you are trying to assign (arg: keyof T) => any
to (arg: T[K]) => any
. keyof T
represents any property name of T
For example in this class:
class X { test: string; test2: number; }
keyof X
is the same as 'test' | 'test2'
while T[K]
with K extends keyof T
represents the type of the property of T
with the name K
, so for the class above T[K]
can be either number
or string
depending on the value passed for K
So if you have Emitter<X>
you would basically trying to assign (arg: string | number) => any
to (arg: 'test' | 'test2') => any
which is definitely not type safe.
My guess is that you want to constrain listener
to have an argument with the same property type as a member of the class. For that you should use Map<string, ((arg: T[keyof T]) => any) []>
to have arg
constrained to any possible property type of 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