From c8d61bfdf474e477986235656b8ae791e1526bc6 Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Fri, 3 May 2024 23:04:16 +0100 Subject: [PATCH] feat: add type parameter to EventTarget This introduces a type parameter to `EventTarget` such that the following is now possible: ```ts interface CustomMap { 'test-event': CustomEvent<{x: number; y: number}>; } declare const customTarget: EventTarget; customTarget.addEventListener('test-event', (event) => { // event is now `CustomEvent<{x: number; y: number}>` event.detail.x; event.detail.y; }); ``` Defaults to `T = any` to maintain existing behaviour otherwise. --- baselines/audioworklet.generated.d.ts | 8 +-- baselines/dom.generated.d.ts | 8 +-- baselines/serviceworker.generated.d.ts | 8 +-- baselines/sharedworker.generated.d.ts | 8 +-- baselines/webworker.generated.d.ts | 8 +-- inputfiles/overridingTypes.jsonc | 70 +++++++++++++++++++++++++- unittests/files/eventtarget.ts | 15 ++++++ 7 files changed, 108 insertions(+), 17 deletions(-) create mode 100644 unittests/files/eventtarget.ts diff --git a/baselines/audioworklet.generated.d.ts b/baselines/audioworklet.generated.d.ts index 5ef63d8a5..6eb4cd98f 100644 --- a/baselines/audioworklet.generated.d.ts +++ b/baselines/audioworklet.generated.d.ts @@ -583,7 +583,7 @@ interface EventListenerObject { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget) */ -interface EventTarget { +interface EventTarget { /** * Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched. * @@ -601,7 +601,8 @@ interface EventTarget { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener) */ - addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: AddEventListenerOptions | boolean): void; + addEventListener(type: K, callback: (this: EventTarget, ev: T[K]) => any, options?: AddEventListenerOptions | boolean): void; + addEventListener(type: string, callback: EventListenerOrEventListenerObject, options?: AddEventListenerOptions | boolean): void; /** * Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise. * @@ -613,7 +614,8 @@ interface EventTarget { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener) */ - removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void; + removeEventListener(type: K, callback: (this: EventTarget, ev: T[K]) => any, options?: EventListenerOptions | boolean): void; + removeEventListener(type: string, callback: EventListenerOrEventListenerObject, options?: EventListenerOptions | boolean): void; } declare var EventTarget: { diff --git a/baselines/dom.generated.d.ts b/baselines/dom.generated.d.ts index 1c516924b..bc8920583 100644 --- a/baselines/dom.generated.d.ts +++ b/baselines/dom.generated.d.ts @@ -8298,7 +8298,7 @@ declare var EventSource: { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget) */ -interface EventTarget { +interface EventTarget { /** * Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched. * @@ -8316,7 +8316,8 @@ interface EventTarget { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener) */ - addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: AddEventListenerOptions | boolean): void; + addEventListener(type: K, callback: (this: EventTarget, ev: T[K]) => any, options?: AddEventListenerOptions | boolean): void; + addEventListener(type: string, callback: EventListenerOrEventListenerObject, options?: AddEventListenerOptions | boolean): void; /** * Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise. * @@ -8328,7 +8329,8 @@ interface EventTarget { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener) */ - removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void; + removeEventListener(type: K, callback: (this: EventTarget, ev: T[K]) => any, options?: EventListenerOptions | boolean): void; + removeEventListener(type: string, callback: EventListenerOrEventListenerObject, options?: EventListenerOptions | boolean): void; } declare var EventTarget: { diff --git a/baselines/serviceworker.generated.d.ts b/baselines/serviceworker.generated.d.ts index ef196e281..0466e9275 100644 --- a/baselines/serviceworker.generated.d.ts +++ b/baselines/serviceworker.generated.d.ts @@ -2402,7 +2402,7 @@ declare var EventSource: { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget) */ -interface EventTarget { +interface EventTarget { /** * Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched. * @@ -2420,7 +2420,8 @@ interface EventTarget { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener) */ - addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: AddEventListenerOptions | boolean): void; + addEventListener(type: K, callback: (this: EventTarget, ev: T[K]) => any, options?: AddEventListenerOptions | boolean): void; + addEventListener(type: string, callback: EventListenerOrEventListenerObject, options?: AddEventListenerOptions | boolean): void; /** * Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise. * @@ -2432,7 +2433,8 @@ interface EventTarget { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener) */ - removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void; + removeEventListener(type: K, callback: (this: EventTarget, ev: T[K]) => any, options?: EventListenerOptions | boolean): void; + removeEventListener(type: string, callback: EventListenerOrEventListenerObject, options?: EventListenerOptions | boolean): void; } declare var EventTarget: { diff --git a/baselines/sharedworker.generated.d.ts b/baselines/sharedworker.generated.d.ts index f522124e8..2efbcb6c8 100644 --- a/baselines/sharedworker.generated.d.ts +++ b/baselines/sharedworker.generated.d.ts @@ -2329,7 +2329,7 @@ declare var EventSource: { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget) */ -interface EventTarget { +interface EventTarget { /** * Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched. * @@ -2347,7 +2347,8 @@ interface EventTarget { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener) */ - addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: AddEventListenerOptions | boolean): void; + addEventListener(type: K, callback: (this: EventTarget, ev: T[K]) => any, options?: AddEventListenerOptions | boolean): void; + addEventListener(type: string, callback: EventListenerOrEventListenerObject, options?: AddEventListenerOptions | boolean): void; /** * Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise. * @@ -2359,7 +2360,8 @@ interface EventTarget { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener) */ - removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void; + removeEventListener(type: K, callback: (this: EventTarget, ev: T[K]) => any, options?: EventListenerOptions | boolean): void; + removeEventListener(type: string, callback: EventListenerOrEventListenerObject, options?: EventListenerOptions | boolean): void; } declare var EventTarget: { diff --git a/baselines/webworker.generated.d.ts b/baselines/webworker.generated.d.ts index 4dd793c12..69c2493b8 100644 --- a/baselines/webworker.generated.d.ts +++ b/baselines/webworker.generated.d.ts @@ -2612,7 +2612,7 @@ declare var EventSource: { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget) */ -interface EventTarget { +interface EventTarget { /** * Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched. * @@ -2630,7 +2630,8 @@ interface EventTarget { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener) */ - addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: AddEventListenerOptions | boolean): void; + addEventListener(type: K, callback: (this: EventTarget, ev: T[K]) => any, options?: AddEventListenerOptions | boolean): void; + addEventListener(type: string, callback: EventListenerOrEventListenerObject, options?: AddEventListenerOptions | boolean): void; /** * Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise. * @@ -2642,7 +2643,8 @@ interface EventTarget { * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener) */ - removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void; + removeEventListener(type: K, callback: (this: EventTarget, ev: T[K]) => any, options?: EventListenerOptions | boolean): void; + removeEventListener(type: string, callback: EventListenerOrEventListenerObject, options?: EventListenerOptions | boolean): void; } declare var EventTarget: { diff --git a/inputfiles/overridingTypes.jsonc b/inputfiles/overridingTypes.jsonc index 416f88377..5cdd0bdf2 100644 --- a/inputfiles/overridingTypes.jsonc +++ b/inputfiles/overridingTypes.jsonc @@ -2998,29 +2998,95 @@ } }, "EventTarget": { + "typeParameters": [ + { + "name": "T", + "default": "any" + } + ], "methods": { "method": { "addEventListener": { "signature": { "0": { + "typeParameters": [ + { + "name": "K extends keyof T", + "default": "" + } + ], "param": [ + { + "name": "type", + "overrideType": "K" + }, + { + "name": "callback", + "overrideType": "(this: EventTarget, ev: T[K]) => any", + "nullable": false + } + ], + "overrideType": "void" + }, + "1": { + "param": [ + { + "name": "type", + "overrideType": "string" + }, { "name": "callback", "overrideType": "EventListenerOrEventListenerObject" + }, + { + "name": "options", + "overrideType": "AddEventListenerOptions | boolean", + "optional": true } - ] + ], + "overrideType": "void" } } }, "removeEventListener": { "signature": { "0": { + "typeParameters": [ + { + "name": "K extends keyof T", + "default": "" + } + ], "param": [ + { + "name": "type", + "overrideType": "K" + }, + { + "name": "callback", + "overrideType": "(this: EventTarget, ev: T[K]) => any", + "nullable": false + } + ], + "overrideType": "void" + }, + "1": { + "param": [ + { + "name": "type", + "overrideType": "string" + }, { "name": "callback", "overrideType": "EventListenerOrEventListenerObject" + }, + { + "name": "options", + "overrideType": "EventListenerOptions | boolean", + "optional": true } - ] + ], + "overrideType": "void" } } } diff --git a/unittests/files/eventtarget.ts b/unittests/files/eventtarget.ts new file mode 100644 index 000000000..438bab75f --- /dev/null +++ b/unittests/files/eventtarget.ts @@ -0,0 +1,15 @@ +declare const target: EventTarget; + +target.addEventListener("custom", (event) => { + event.target; +}); + +interface CustomEventMap { + custom: CustomEvent<{ data: number }>; +} + +declare const customTarget: EventTarget; + +customTarget.addEventListener("custom", (event) => { + event.detail.data; +});