Skip to content

Instantly share code, notes, and snippets.

@zgover
Last active August 15, 2021 05:49
Show Gist options
  • Save zgover/42c0d91adbb9315d883b8a00eb8fae40 to your computer and use it in GitHub Desktop.
Save zgover/42c0d91adbb9315d883b8a00eb8fae40 to your computer and use it in GitHub Desktop.
[TS/JS MittEmitter] Typed Event Emitter Function Factory #javascript #typescript #mitt #eventemitter #emit #events
// This file is based on https://github.com/developit/mitt/blob/v1.1.3/src/index.js
// It's been edited for the needs of this script
// See the LICENSE at the top of the file
// Event handler callback function
type EventHandler = (...events: any[]) => void
// Wild card handler function receiving the first parameter as the event name
type WildCardEventHandler = (name: string, ...events: any[]) => void
// An array of all currently registered event handlers for an event name
type EventHandlerList = Array<EventHandler>
// An array of all currently registered wildcard event handlers for an event name
type WildCardEventHandlerList = Array<WildCardEventHandler>
// A map of event types and their corresponding event handlers.
type EventHandlerMap = {
'*'?: WildCardEventHandlerList,
[type: string]: EventHandlerList,
}
/**
* Basic event emitter with on/off/emit listening events.
* Concepts include functional event emitting and publish–subscribe
* patterns (Pub/Sub) https://cloud.google.com/pubsub/docs/overview
*/
export type MittEmitter = {
/**
* Register an event handler for the given type.
*
* @example ```
* const handler = (param1: string) => log(txt)
* mittEmitter.on('txtChangeEvent', handler) // Same handler used with off()
* ```
* @param {string} name RefName/ID of event to listen for, or `"*"` for all events
* @param {EventHandler} handler Function to call in response to given event
* @memberOf MittEmitter
*/
on(name: string, handler: EventHandler): void
/**
* Remove an event handler for the given type.
*
* @example ```
* const handler = (param1: string) => log(txt)
* mittEmitter.off('txtChangeEvent', handler) // Same handler used with on()
* ```
* @see MittEmitter.on
* @param {string} name RefName/ID of event to unregister `handler` from, or `"*"`
* @param {EventHandler} handler EventHandler function to remove
* @memberOf MittEmitter
*/
off(name: string, handler: EventHandler): void
/**
* Invoke all handlers for the given type.
* If present, `"*"` handlers are invoked after type-matched handlers.
*
* @example ```mittEmitter.emit('txtChangeEvent', "Hello world, I'm event param #1")```
* @param {string} type RefName/ID of event to invoke
* @param {any[]} events Any rest params (object is recommended and powerful), passed to each handler
* @memberOf MittEmitter
*/
emit(name: string, ...events: any[]): void
}
/**
* MittEmitter: Small functional event emitter using publish/subscribe (Pub/Sub) pattern.
*
* @name mittEmitter
* @param {EventHandlerMap?} all Existing or default handler map
* @returns {MittEmitter}
*/
export default function mittEmitter(all?: EventHandlerMap): MittEmitter {
all = all || Object.create(null)
return {
on(name: string, handler: EventHandler) {
(all[name] || (all[name] = [])).push(handler)
},
off(name: string, handler: EventHandler) {
if (all[name]) {
all[name].splice(all[name].indexOf(handler) >>> 0, 1)
}
},
emit(name: string, ...events: any[]) {
function handleFn(
fn: EventHandler | WildCardEventHandler | null,
wild: boolean = false
) {
if (typeof fn === 'function') {
if (wild) {
fn(name, ...events)
} else {
fn(...events)
}
}
}
;(all[name] ??= []).slice().map((fn?: EventHandler) => { handleFn(fn) })
;(all['*'] ??= []).slice().map((fn?: WildCardEventHandler) => { handleFn(fn, true) })
}
} as MittEmitter
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment