methods according given EventMap
*/
export default function typedEventTargetFactory<EventMap extends { [K: string]: any }, EM extends { [K: string]: any } = EventMap & { all: EventMap[keyof EventMap] }>() {
const symbol = Symbol("ownCustomEvent");
class TypedEvent<K extends keyof EM = keyof EM> extends CustomEvent<EM[K]> {
[symbol] = true;
constructor(type: K, ...eventInitDict: EM[K] extends Record<string, never> | null | undefined ? [undefined?] : [CustomEventInit<EM[K]>]) {
super(type as string, ...eventInitDict);
}
}
class TypedEventTarget extends EventTarget {
static TypedEvent = TypedEvent;
addEventListener<K extends keyof EM>(type: K, listener: ((this: typeof this, ev: TypedEvent<K>) => any) | { handleEvent: (ev: CustomEvent<EM[K]>) => any } | null, options?: boolean | EventListenerOptions) {
return super.addEventListener(type as string, listener as EventListenerOrEventListenerObject, options);
}
removeEventListener<K extends keyof EM>(type: K, listener: ((this: typeof this, ev: TypedEvent<K>) => any) | { handleEvent: (ev: CustomEvent<EM[K]>) => any } | null, options?: boolean | EventListenerOptions) {
return super.removeEventListener(type as string, listener as EventListenerOrEventListenerObject, options);
}
dispatchEvent(event: TypedEvent) {
super.dispatchEvent(new CustomEvent("all", {detail: event.detail}));
return super.dispatchEvent(event as Event);
}
}
return TypedEventTarget;
}
class SomeTargetEvent extends typedEventTargetFactory<{ myEvent: { flag: boolean } }>() {}
const someTargetEvent = new SomeTargetEvent();
someTargetEvent.addEventListener("myEvent", (event) => event.detail.flag); // OK
someTargetEvent.addEventListener("all", (event) => event.detail.flag); // OK
someTargetEvent.dispatchEvent(new SomeTargetEvent.TypedEvent("myEvent", {detail: {flag: true}})); // OK
someTargetEvent.addEventListener("myEvent11111", null); // Argument of type "myEvent11111" is not assignable to parameter of type "all" | "myEvent"
someTargetEvent.addEventListener("myEvent", (event) => event.detail.noFlag); // Property noFlag does not exist on type { flag: boolean; }
someTargetEvent.dispatchEvent(new SomeTargetEvent.TypedEvent("myEvent", {detail: {noFlag: true}})); // Type { noFlag: true; } is not assignable to type { flag: boolean; }
ок я понял теперь о чём ты
Обсуждают сегодня