1

I'm currently in the process of transitioning from JS to TS and can't quite get my head around keyof. I found https://github.com/kimamula/TypeScript-definition-of-EventEmitter-with-keyof and now I'm trying to implement this. All went fine until I turned on 'noImplicitAny'.

I have made an example in the ts playground to show the issue I'm having:

In the constructor there's no access to K so I had to explicitly make the Map (arg: any) to get it to work.

Is there a solution that avoids using any when creating the Map?

Eldho
  • 7,795
  • 5
  • 40
  • 77
Noel Heesen
  • 223
  • 1
  • 4
  • 14

1 Answers1

0

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
Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357