How to implement the publish-subscribe pattern in TypeScript?
I'm working on creating an events system for my game, and my code currently looks like this:
export const enum ET { Collision, Dying, Damage }
type ActionCallback = (scene: Scene, event: GameEvent) => void;
subscribe(eventType: ET, callback: ActionCallback) {
this.subscriptions[eventType].push(callback);
}
And then an example of some code which uses this function is like this:
scene.events.subscribe(ET.Dying, handleEntityDeath);
handleEntityDeath = (scene: Scene, event: DyingEvent) => {
scene.deleteEntity(event.entity);
}
The problem is that TypeScript fails to compile and says something like: event's type must be GameEvent and not DyingEvent
.
Basically, I need a way to "link" ET.Dying
and DyingEvent
, but I'm not sure how to do it. I think if I can accomplish this, then I can event handlers like the above where it will only compile if the first parameter is something like ET.Dying
and the second parameter is a callback which takes a DyingEvent
. I would want it to fail to compile if the callback instead had a DamageEvent
parameter, if that makes sense.
Can this be done, and if so, how?
Figured it out:
interface EventMap {
[ET.Collision]: CollisionEvent;
[ET.Dying]: DyingEvent;
// etc
}
subscribe = <T extends ET>(eventType: T, callback: (scene: Scene, event: EventMap[T]) => void) => {
this.subscriptions[eventType].push(callback);
}
// Example calling code below here:
scene.events.subscribe(ET.Dying, handleEntityDeath);
handleEntityDeath = (scene: Scene, event: DyingEvent) => {
scene.deleteEntity(event.entity);
}