We also limit the values: T[eventName]
retrieves the type of the value associated with
key eventName
. In the mouse example, this type would be { x: number, y: number }
. We require
that a key can only be associated with an array of functions to void, each of which accepts
T[K]
as first argument. This is precisely what we want; for example, mouseClick
would map to
an array of functions that accept the mouse click location.
Line 8: We restrict the type of emit
to only accept values that correspond to the keys
of the type T
. We can’t simply write event: keyof T
, because this would not give us enough
information to retrieve the type of value
: if event
is just keyof T
,
then value
can be any of the values of T
. Instead, we use generics; this way, when the
function is called with "mouseClick"
, the type of K
is inferred to also be "mouseClick"
, which
gives TypeScript enough information to narrow the type of value
.
Line 12: We use the exact same trick here as we did on line 8.
Let’s give this a spin with our numberChange
/stringChange
example from earlier:
const emitter = new EventEmitter<{ numberChange: number, stringChange: string }>();
emitter.addHandler("numberChange", n => console.log("New number value is: ", n));
emitter.addHandler("stringChange", s => console.log("New string value is: ", s));
emitter.emit("numberChange", 1);
emitter.emit("stringChange", "3");
emitter.emit("numberChange", "1");
emitter.emit("stringChange", 3);
The function calls on lines 24 and 25 are correct, but the subsequent two (on lines 26 and 27)
are not, as they attempt to emit the opposite type of the one they’re supposed to. And indeed,
TypeScript complains about only these two lines: