Skip to content

Instantly share code, notes, and snippets.

@christophemarois
Last active January 18, 2023 00:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save christophemarois/a4c36bbccd2938e1d292143b112e5fd1 to your computer and use it in GitHub Desktop.
Save christophemarois/a4c36bbccd2938e1d292143b112e5fd1 to your computer and use it in GitHub Desktop.
Generic EventEmitter
class Emitter<Events extends Record<any, (val: any) => any>> {
private observers: Map<keyof Events, Set<(val: any) => any>> = new Map()
on<Name extends keyof Events, Fn extends Events[Name]>(name: Name, fn: Fn) {
if (!this.observers.has(name)) {
this.observers.set(name, new Set())
}
this.observers.get(name)!.add(fn)
return () => this.off(name, fn)
}
off<Name extends keyof Events, Fn extends Events[Name]>(name: Name, fn: Fn) {
this.observers.get(name)?.delete(fn)
}
emit<Name extends keyof Events, Val extends Parameters<Events[Name]>[0]>(
name: Name,
val: Val
) {
if (!this.observers.has(name)) {
return
}
for (const fn of this.observers.get(name)!) {
fn(val)
}
}
}
// Support for anything as an event name
const exit = Symbol()
const emitter = new Emitter<{
shoutName: (username: string) => void
sayNextAge: (age: number) => void
[exit]: (code: number) => void
}>()
emitter.on('shoutName', (name) => console.log(`Hi ${name.toUpperCase()}!`))
emitter.on('sayNextAge', (age) =>
console.log(`You are soon gonna be ${age + 1} years old!`)
)
const unsub = emitter.on(exit, (code) => process.exit(code))
unsub() // on returns an unsubscribe function
emitter.emit('shoutName', 'Christophe')
emitter.emit('sayNextAge', 31)
emitter.emit(exit, 1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment