Skip to content

Instantly share code, notes, and snippets.

@ryuujo1573
Last active April 17, 2023 09:23
Show Gist options
  • Save ryuujo1573/b9bd37f549988924125e799a5b063288 to your computer and use it in GitHub Desktop.
Save ryuujo1573/b9bd37f549988924125e799a5b063288 to your computer and use it in GitHub Desktop.
Demonstrates how to define type of custom `Event`s
// aliases
type MyEvent = PingEvent | MessageEvent;
type EventTypes = MyEvent["type"];
type EventHandler<T> = (payload: T) => void;
type EventHandlers = {
ping: EventHandler<PingEvent>[];
message: EventHandler<MessageEvent>[];
};
// type defs
interface PingEvent extends Event {
type: "ping";
foo: number;
}
interface MessageEvent extends Event {
type: "message";
bar: string;
}
// type guard
function isMyEvent(t: Event): t is MyEvent {
return ["ping", "message"].includes(t.type);
}
class _ {
// approach 0: (fine)
// seperated handers
#__pingEventHandlers: EventHandler<PingEvent>[];
#__messageEventHandlers: EventHandler<MessageEvent>[];
// approach 1-3
readonly eventHandlers: EventHandlers = {
ping: [],
message: [],
};
dispatchEvent<T extends MyEvent>(event: T): void {
if (isMyEvent(event)) {
// approach 1: (low readability)
// requires a shim for type inferring
for (const cb of this.eventHandlers[event.type]) {
cb(event as never);
}
// approach 2: (not recommended)
// occurs implicit any
this.eventHandlers[event.type].forEach((cb) => cb(event));
// approach 0/3: (recommended)
// narrowing using switch expression
switch (event.type) {
case "ping":
// approach 3:
this.eventHandlers.ping.forEach((cb) => cb(event));
// approach 0:
for (const callback of this.#__pingEventHandlers) {
callback(event);
}
break;
// case ...
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment