diff --git a/src/utils/mitt.ts b/src/utils/mitt.ts index 4b15bbabeac88d2f62454f1dd2d101838f6b3703..cf09fd81055f0a56e437496c02b20bf6c8b2f4c1 100644 --- a/src/utils/mitt.ts +++ b/src/utils/mitt.ts @@ -2,32 +2,37 @@ * copy to https://github.com/developit/mitt * Expand clear method */ - export type EventType = string | symbol; // An event handler can take an optional event argument // and should not return a value -export type Handler = (event?: T) => void; -export type WildcardHandler = (type: EventType, event?: any) => void; +export type Handler = (event: T) => void; +export type WildcardHandler> = ( + type: keyof T, + event: T[keyof T], +) => void; // An array of all currently registered event handlers for a type -export type EventHandlerList = Array; -export type WildCardEventHandlerList = Array; +export type EventHandlerList = Array>; +export type WildCardEventHandlerList> = Array>; // A map of event types and their corresponding event handlers. -export type EventHandlerMap = Map; +export type EventHandlerMap> = Map< + keyof Events | '*', + EventHandlerList | WildCardEventHandlerList +>; -export interface Emitter { - all: EventHandlerMap; +export interface Emitter> { + all: EventHandlerMap; - on(type: EventType, handler: Handler): void; - on(type: '*', handler: WildcardHandler): void; + on(type: Key, handler: Handler): void; + on(type: '*', handler: WildcardHandler): void; - off(type: EventType, handler: Handler): void; - off(type: '*', handler: WildcardHandler): void; + off(type: Key, handler?: Handler): void; + off(type: '*', handler: WildcardHandler): void; - emit(type: EventType, event?: T): void; - emit(type: '*', event?: any): void; + emit(type: Key, event: Events[Key]): void; + emit(type: undefined extends Events[Key] ? Key : never): void; clear(): void; } @@ -36,7 +41,10 @@ export interface Emitter { * @name mitt * @returns {Mitt} */ -export default function mitt(all?: EventHandlerMap): Emitter { +export function mitt>( + all?: EventHandlerMap, +): Emitter { + type GenericEventHandler = Handler | WildcardHandler; all = all || new Map(); return { @@ -47,48 +55,61 @@ export default function mitt(all?: EventHandlerMap): Emitter { /** * Register an event handler for the given type. - * @param {string|symbol} type Type of event to listen for, or `"*"` for all events + * @param {string|symbol} type Type of event to listen for, or `'*'` for all events * @param {Function} handler Function to call in response to given event * @memberOf mitt */ - on(type: EventType, handler: Handler) { - const handlers = all?.get(type); - const added = handlers && handlers.push(handler); - if (!added) { - all?.set(type, [handler]); + on(type: Key, handler: GenericEventHandler) { + const handlers: Array | undefined = all!.get(type); + if (handlers) { + handlers.push(handler); + } else { + all!.set(type, [handler] as EventHandlerList); } }, /** * Remove an event handler for the given type. - * @param {string|symbol} type Type of event to unregister `handler` from, or `"*"` - * @param {Function} handler Handler function to remove + * If `handler` is omitted, all handlers of the given type are removed. + * @param {string|symbol} type Type of event to unregister `handler` from (`'*'` to remove a wildcard handler) + * @param {Function} [handler] Handler function to remove * @memberOf mitt */ - off(type: EventType, handler: Handler) { - const handlers = all?.get(type); + off(type: Key, handler?: GenericEventHandler) { + const handlers: Array | undefined = all!.get(type); if (handlers) { - handlers.splice(handlers.indexOf(handler) >>> 0, 1); + if (handler) { + handlers.splice(handlers.indexOf(handler) >>> 0, 1); + } else { + all!.set(type, []); + } } }, /** * Invoke all handlers for the given type. - * If present, `"*"` handlers are invoked after type-matched handlers. + * If present, `'*'` handlers are invoked after type-matched handlers. * - * Note: Manually firing "*" handlers is not supported. + * Note: Manually firing '*' handlers is not supported. * * @param {string|symbol} type The event type to invoke * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler * @memberOf mitt */ - emit(type: EventType, evt: T) { - ((all?.get(type) || []) as EventHandlerList).slice().map((handler) => { - handler(evt); - }); - ((all?.get('*') || []) as WildCardEventHandlerList).slice().map((handler) => { - handler(type, evt); - }); + emit(type: Key, evt?: Events[Key]) { + let handlers = all!.get(type); + if (handlers) { + (handlers as EventHandlerList).slice().forEach((handler) => { + handler(evt as Events[Key]); + }); + } + + handlers = all!.get('*'); + if (handlers) { + (handlers as WildCardEventHandlerList).slice().forEach((handler) => { + handler(type, evt as Events[Key]); + }); + } }, /**