Repository: exadel-inc/esl
Pull request #2372 (2024-04-29 17:41:29)

fix(esl-event-listener): fix `listen` decorator strict types are incorrect


Patch:
diff --git a/src/modules/esl-utils/decorators/listen.ts b/src/modules/esl-utils/decorators/listen.ts
index e4eecc7dd..c9e26e85c 100644
--- a/src/modules/esl-utils/decorators/listen.ts
+++ b/src/modules/esl-utils/decorators/listen.ts
@@ -24,7 +24,7 @@ export function listen<K extends keyof ESLListenerEventMap>(event: K | PropertyP
  */
 export function listen<K extends keyof ESLListenerEventMap>(
   desc: ESLListenerDescriptorExt<K> & {selector: string | PropertyProvider<string>}
-): ListenDecorator<DelegatedEvent<ESLListenerEventMap[K]>>;
+): ListenDecorator<DelegatedEvent<ESLListenerEventMap[K]> | ESLListenerEventMap[K]>;
 /**
  * Decorator to declare listener ({@link ESLEventListener}) meta information using {@link ESLListenerDescriptor}
  * Defines auto-subscribable event by default


Test patch:
diff --git a/src/modules/esl-event-listener/test/listener.delegate.test.ts b/src/modules/esl-event-listener/test/listener.delegate.test.ts
index ec185322e..d99b302a1 100644
--- a/src/modules/esl-event-listener/test/listener.delegate.test.ts
+++ b/src/modules/esl-event-listener/test/listener.delegate.test.ts
@@ -1,4 +1,5 @@
 import {ESLEventUtils} from '../core/api';
+import type {DelegatedEvent} from '../core/api';
 
 describe('ESlEventListener subscription and delegation', () => {
   const host = document.createElement('section');
@@ -104,4 +105,14 @@ describe('ESlEventListener subscription and delegation', () => {
       expect(handler).toHaveBeenCalledWith(expect.objectContaining({$delegate: $btn}));
     });
   });
+
+  test('Delegation types are correct (build time)', () => {
+    ESLEventUtils.subscribe(host, {event: 'click', selector: '.btn'}, (e: MouseEvent) => void 0);
+    ESLEventUtils.subscribe(host, {event: 'keyup keydown', selector: '.btn'}, (e: KeyboardEvent) => void 0);
+    ESLEventUtils.subscribe(host, {event: 'touchstart mousedown', selector: '.btn'}, (e: MouseEvent) => void 0);
+    ESLEventUtils.subscribe(host, {event: 'click', selector: '.btn'}, (e: DelegatedEvent<MouseEvent>) => void 0);
+    ESLEventUtils.subscribe(host, {event: 'keyup keydown', selector: '.btn'}, (e: DelegatedEvent<KeyboardEvent>) => void 0);
+    ESLEventUtils.subscribe(host, {event: 'touchstart mousedown', selector: '.btn'}, (e: DelegatedEvent<PointerEvent>) => void 0);
+    expect(true).toBe(true);
+  });
 });
diff --git a/src/modules/esl-utils/decorators/test/listen.test.ts b/src/modules/esl-utils/decorators/test/listen.test.ts
index de2d9e5d1..8fd7228dc 100644
--- a/src/modules/esl-utils/decorators/test/listen.test.ts
+++ b/src/modules/esl-utils/decorators/test/listen.test.ts
@@ -189,4 +189,22 @@ describe('Decorator: @listen', () => {
     const button = test.querySelector('button');
     button?.click();
   });
+
+  test('Delegation types are correct (build time)', () => {
+    class Test extends HTMLElement {
+      @listen({event: 'click', selector: '.btn'})
+      onEvent1(e: MouseEvent) {}
+      @listen({event: 'keyup keydown', selector: '.btn'})
+      onEvent2(e: KeyboardEvent) {}
+      @listen({event: 'touchstart mousedown', selector: '.btn'})
+      onEvent3(e: PointerEvent) {}
+      @listen({event: 'click', selector: '.btn'})
+      onEvent4(e: DelegatedEvent<MouseEvent>) {}
+      @listen({event: 'keyup keydown', selector: '.btn'})
+      onEvent5(e: DelegatedEvent<KeyboardEvent>) {}
+      @listen({event: 'touchstart mousedown', selector: '.btn'})
+      onEvent6(e: DelegatedEvent<PointerEvent>) {}
+    }
+    expect(Test).toBe(Test);
+  });
 });