Commit ae5f5cb13c63aec801f9d900a0f3b85bf86b675e
Committed by
GitHub
1 parent
ccaa84c3
feat: sync mitt (#2677)
Showing
1 changed file
with
56 additions
and
35 deletions
src/utils/mitt.ts
... | ... | @@ -2,32 +2,37 @@ |
2 | 2 | * copy to https://github.com/developit/mitt |
3 | 3 | * Expand clear method |
4 | 4 | */ |
5 | - | |
6 | 5 | export type EventType = string | symbol; |
7 | 6 | |
8 | 7 | // An event handler can take an optional event argument |
9 | 8 | // and should not return a value |
10 | -export type Handler<T = any> = (event?: T) => void; | |
11 | -export type WildcardHandler = (type: EventType, event?: any) => void; | |
9 | +export type Handler<T = unknown> = (event: T) => void; | |
10 | +export type WildcardHandler<T = Record<string, unknown>> = ( | |
11 | + type: keyof T, | |
12 | + event: T[keyof T], | |
13 | +) => void; | |
12 | 14 | |
13 | 15 | // An array of all currently registered event handlers for a type |
14 | -export type EventHandlerList = Array<Handler>; | |
15 | -export type WildCardEventHandlerList = Array<WildcardHandler>; | |
16 | +export type EventHandlerList<T = unknown> = Array<Handler<T>>; | |
17 | +export type WildCardEventHandlerList<T = Record<string, unknown>> = Array<WildcardHandler<T>>; | |
16 | 18 | |
17 | 19 | // A map of event types and their corresponding event handlers. |
18 | -export type EventHandlerMap = Map<EventType, EventHandlerList | WildCardEventHandlerList>; | |
20 | +export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map< | |
21 | + keyof Events | '*', | |
22 | + EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events> | |
23 | +>; | |
19 | 24 | |
20 | -export interface Emitter { | |
21 | - all: EventHandlerMap; | |
25 | +export interface Emitter<Events extends Record<EventType, unknown>> { | |
26 | + all: EventHandlerMap<Events>; | |
22 | 27 | |
23 | - on<T = any>(type: EventType, handler: Handler<T>): void; | |
24 | - on(type: '*', handler: WildcardHandler): void; | |
28 | + on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void; | |
29 | + on(type: '*', handler: WildcardHandler<Events>): void; | |
25 | 30 | |
26 | - off<T = any>(type: EventType, handler: Handler<T>): void; | |
27 | - off(type: '*', handler: WildcardHandler): void; | |
31 | + off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>): void; | |
32 | + off(type: '*', handler: WildcardHandler<Events>): void; | |
28 | 33 | |
29 | - emit<T = any>(type: EventType, event?: T): void; | |
30 | - emit(type: '*', event?: any): void; | |
34 | + emit<Key extends keyof Events>(type: Key, event: Events[Key]): void; | |
35 | + emit<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): void; | |
31 | 36 | clear(): void; |
32 | 37 | } |
33 | 38 | |
... | ... | @@ -36,7 +41,10 @@ export interface Emitter { |
36 | 41 | * @name mitt |
37 | 42 | * @returns {Mitt} |
38 | 43 | */ |
39 | -export default function mitt(all?: EventHandlerMap): Emitter { | |
44 | +export function mitt<Events extends Record<EventType, unknown>>( | |
45 | + all?: EventHandlerMap<Events>, | |
46 | +): Emitter<Events> { | |
47 | + type GenericEventHandler = Handler<Events[keyof Events]> | WildcardHandler<Events>; | |
40 | 48 | all = all || new Map(); |
41 | 49 | |
42 | 50 | return { |
... | ... | @@ -47,48 +55,61 @@ export default function mitt(all?: EventHandlerMap): Emitter { |
47 | 55 | |
48 | 56 | /** |
49 | 57 | * Register an event handler for the given type. |
50 | - * @param {string|symbol} type Type of event to listen for, or `"*"` for all events | |
58 | + * @param {string|symbol} type Type of event to listen for, or `'*'` for all events | |
51 | 59 | * @param {Function} handler Function to call in response to given event |
52 | 60 | * @memberOf mitt |
53 | 61 | */ |
54 | - on<T = any>(type: EventType, handler: Handler<T>) { | |
55 | - const handlers = all?.get(type); | |
56 | - const added = handlers && handlers.push(handler); | |
57 | - if (!added) { | |
58 | - all?.set(type, [handler]); | |
62 | + on<Key extends keyof Events>(type: Key, handler: GenericEventHandler) { | |
63 | + const handlers: Array<GenericEventHandler> | undefined = all!.get(type); | |
64 | + if (handlers) { | |
65 | + handlers.push(handler); | |
66 | + } else { | |
67 | + all!.set(type, [handler] as EventHandlerList<Events[keyof Events]>); | |
59 | 68 | } |
60 | 69 | }, |
61 | 70 | |
62 | 71 | /** |
63 | 72 | * Remove an event handler for the given type. |
64 | - * @param {string|symbol} type Type of event to unregister `handler` from, or `"*"` | |
65 | - * @param {Function} handler Handler function to remove | |
73 | + * If `handler` is omitted, all handlers of the given type are removed. | |
74 | + * @param {string|symbol} type Type of event to unregister `handler` from (`'*'` to remove a wildcard handler) | |
75 | + * @param {Function} [handler] Handler function to remove | |
66 | 76 | * @memberOf mitt |
67 | 77 | */ |
68 | - off<T = any>(type: EventType, handler: Handler<T>) { | |
69 | - const handlers = all?.get(type); | |
78 | + off<Key extends keyof Events>(type: Key, handler?: GenericEventHandler) { | |
79 | + const handlers: Array<GenericEventHandler> | undefined = all!.get(type); | |
70 | 80 | if (handlers) { |
71 | - handlers.splice(handlers.indexOf(handler) >>> 0, 1); | |
81 | + if (handler) { | |
82 | + handlers.splice(handlers.indexOf(handler) >>> 0, 1); | |
83 | + } else { | |
84 | + all!.set(type, []); | |
85 | + } | |
72 | 86 | } |
73 | 87 | }, |
74 | 88 | |
75 | 89 | /** |
76 | 90 | * Invoke all handlers for the given type. |
77 | - * If present, `"*"` handlers are invoked after type-matched handlers. | |
91 | + * If present, `'*'` handlers are invoked after type-matched handlers. | |
78 | 92 | * |
79 | - * Note: Manually firing "*" handlers is not supported. | |
93 | + * Note: Manually firing '*' handlers is not supported. | |
80 | 94 | * |
81 | 95 | * @param {string|symbol} type The event type to invoke |
82 | 96 | * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler |
83 | 97 | * @memberOf mitt |
84 | 98 | */ |
85 | - emit<T = any>(type: EventType, evt: T) { | |
86 | - ((all?.get(type) || []) as EventHandlerList).slice().map((handler) => { | |
87 | - handler(evt); | |
88 | - }); | |
89 | - ((all?.get('*') || []) as WildCardEventHandlerList).slice().map((handler) => { | |
90 | - handler(type, evt); | |
91 | - }); | |
99 | + emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) { | |
100 | + let handlers = all!.get(type); | |
101 | + if (handlers) { | |
102 | + (handlers as EventHandlerList<Events[keyof Events]>).slice().forEach((handler) => { | |
103 | + handler(evt as Events[Key]); | |
104 | + }); | |
105 | + } | |
106 | + | |
107 | + handlers = all!.get('*'); | |
108 | + if (handlers) { | |
109 | + (handlers as WildCardEventHandlerList<Events>).slice().forEach((handler) => { | |
110 | + handler(type, evt as Events[Key]); | |
111 | + }); | |
112 | + } | |
92 | 113 | }, |
93 | 114 | |
94 | 115 | /** |
... | ... |