Commit ae5f5cb13c63aec801f9d900a0f3b85bf86b675e

Authored by Kirk Lin
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 /**
... ...