Skip to content

Instantly share code, notes, and snippets.

@Gerrit0
Last active June 29, 2020 03:44
Show Gist options
  • Save Gerrit0/bd3c43edabca29f64088b6089532091c to your computer and use it in GitHub Desktop.
Save Gerrit0/bd3c43edabca29f64088b6089532091c to your computer and use it in GitHub Desktop.
Simple Event emitter - Dual licenced under MIT and Apache 2.0
/**
* Simple, type safe, event emitter class.
*
* @example
* ```ts
* const x = new EventEmitter<{ a: [string] }>()
* x.on('a', a => a.repeat(123)) // ok
* x.on('b', console.log) // error, 'b' is not assignable to 'a'
* const y = new EventEmitter<{ a: [string]; [k: string]: unknown[] }>()
* y.on('a', a => a.repeat(123)) // ok
* // ok, any unknown events will contain an unknown number of arguments.
* y.on('b', (...args: unknown[]) => console.log(...args))
* ```
*/
export class EventEmitter<T extends Record<PropertyKey, unknown[]>> {
// Function is *usually* not a good type to use, but here it lets us specify stricter
// constracts in the methods while not casting everywhere this is used.
private _listeners: Map<keyof T, Function[]> = new Map()
/**
* Starts listening to an event.
* @param event the event to listen to.
* @param listener function to be called when an this event is emitted.
*/
on<K extends keyof T>(event: K, listener: (...args: T[K]) => void): void {
const list = (this._listeners.get(event) || []).slice()
list.push(listener)
this._listeners.set(event, list)
}
/**
* Stops listening to an event.
* @param event the event to stop listening to.
* @param listener the function to remove from the listener array.
*/
off<K extends keyof T>(event: K, listener: (...args: T[K]) => void): void {
const list = this._listeners.get(event) || []
const index = list.indexOf(listener)
if (index !== -1) {
list.splice(index, 1)
}
}
/**
* Emits an event to all currently subscribed listeners.
* @param event the event to emit.
* @param args any arguments required for the event.
*/
emit<K extends keyof T>(event: K, ...args: T[K]) {
for (const listener of this._listeners.get(event)?.slice() || []) {
listener(...args)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment