添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Quick notes on using CustomEvent with [email protected] .

The Issue: No overload matches this call…

In case you tried to use a CustomEvent with TypeScript, chances are you experienced the No overload matches this call. error.

No overload matches this call.
  Overload 1 of 2, '(type: keyof DocumentEventMap, listener: (this: Document, ev: Event | UIEvent | AnimationEvent | MouseEvent | InputEvent | ... 13 more ... | WheelEvent) => any, options?: boolean | ... 1 more ... | undefined): void', gave the following error.
    Argument of type '"custom:event:name"' is not assignable to parameter of type 'keyof DocumentEventMap'.
  Overload 2 of 2, '(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void', gave the following error.
    Argument of type '(e: CustomEvent<string>) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'.
      Type '(e: CustomEvent<string>) => void' is not assignable to type 'EventListener'.
        Types of parameters 'e' and 'evt' are incompatible.
          Type 'Event' is missing the following properties from type 'CustomEvent<string>': detail, initCustomEvent(2769)

The error happens because in dom.generated.d.ts we have the EventListenerOrEventListenerObject which doesn’t support CustomEvents .

// https://github.com/microsoft/TypeScript/blob/main/src/lib/dom.generated.d.ts#L8150
interface EventListener {
    (evt: Event): void;
interface EventListenerObject {
    handleEvent(object: Event): void;
type EventListenerOrEventListenerObject = EventListener | EventListenerObject;
// https://github.com/microsoft/TypeScript/blob/main/src/lib/dom.generated.d.ts#L8199
addEventListener<K extends keyof AbortSignalEventMap>(type: K, listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;

The Quick and Dirty

// Register event 
const callback = (e: CustomEvent<string>) => console.log(e.detail);
document.addEventListener("custom:event:name", callback as EventListener);
// Alternative syntax inline
document.addEventListener("custom:event:name", ((e: CustomEvent<string>) => console.log(e.detail)) as EventListener);
// Fire event
const ev = new CustomEvent("custom:event:name", {detail: "yadda"});
document.dispatchEvent(ev);

The trick is in casting the callback in a EventListener even if we’re using CustomEvent instead of Event .

Extending EventTarget

As alternative, you can extend EventTarget which is the object that expose addEventListener , removeEventListener , and dispatchEvent .

The issue with this approach is that you can’t leverage document global scope, which possibly was the reason you tried to used it in the first place.

interface YourEventMap {
    "yourEvent": CustomEvent
interface YaddaEventTarget extends EventTarget  {
  addEventListener<K extends keyof YourEventMap>(event: K, listener: ((this: Yadda, ev: YourEventMap[K]) => any) | null, options?: AddEventListenerOptions | boolean): void;
  addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: AddEventListenerOptions | boolean): void;
class YaddaEventTarget extends EventTarget {
const instance = new YaddaEventTarget();
instance.addEventListener("yourEvent", (event: CustomEvent) => console.log(event));
instance.dispatchEvent(new CustomEvent("yourEvent", {detail: "bla"}));

Current status of the issue

As per Feb 2024, I see the issue on github getting bigger and bigger, with the discussion about the fix in stall so i guess that for a while this will stay relevant.

TypeScript doesn't allow event : CustomEvent in addEventListener The possible solution Make EventListener covariant Supporting lib from node_modules