Skip to content

Commit e5f96c2

Browse files
crisbetokirjs
authored andcommitted
fix(compiler-cli): animation events not type checked properly when bound through HostListener decorator
Fixes that we weren't inferring the type of `animate.` event correctly, if they're bound through a `@HostListener` decorator.
1 parent 65bf054 commit e5f96c2

2 files changed

Lines changed: 54 additions & 2 deletions

File tree

packages/compiler-cli/src/ngtsc/typecheck/src/host_bindings.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,9 @@ function createNodeFromListenerDecorator(
416416
target = null;
417417
} else {
418418
const parsedName = parser.parseEventListenerName(eventNameNode.text);
419-
type = ParsedEventType.Regular;
419+
type = parsedName.eventName.startsWith('animate.')
420+
? ParsedEventType.Animation
421+
: ParsedEventType.Regular;
420422
eventName = parsedName.eventName;
421423
target = parsedName.target;
422424
phase = null;

packages/compiler-cli/test/ngtsc/host_bindings_type_check_spec.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ runInEachFileSystem(() => {
278278
expect(getDiagnosticSourceCode(diags[0])).toBe('$event');
279279
});
280280

281-
it('should check host animation event listeners', () => {
281+
it('should check legacy host animation event listeners', () => {
282282
env.write(
283283
'test.ts',
284284
`
@@ -301,6 +301,56 @@ runInEachFileSystem(() => {
301301
expect(getDiagnosticSourceCode(diags[0])).toBe('handleEvent');
302302
});
303303

304+
it('should check animation event listeners in `host` object', () => {
305+
env.write(
306+
'test.ts',
307+
`
308+
import {Component} from '@angular/core';
309+
310+
@Component({
311+
template: '',
312+
selector: 'button[foo]',
313+
host: {'(animate.leave)': 'handleEvent($event)'},
314+
})
315+
export class Comp {
316+
handleEvent(event: Event) {}
317+
}
318+
`,
319+
);
320+
321+
const diags = env.driveDiagnostics();
322+
expect(diags.length).toBe(1);
323+
expect((diags[0].messageText as ts.DiagnosticMessageChain).messageText).toContain(
324+
`Argument of type 'AnimationCallbackEvent' is not assignable to parameter of type 'Event'.`,
325+
);
326+
expect(getDiagnosticSourceCode(diags[0])).toBe('$event');
327+
});
328+
329+
it('should check animation event listeners in `@HostListener`', () => {
330+
env.write(
331+
'test.ts',
332+
`
333+
import {Component, HostListener} from '@angular/core';
334+
335+
@Component({
336+
template: '',
337+
selector: 'button[foo]',
338+
})
339+
export class Comp {
340+
@HostListener('animate.leave', ['$event'])
341+
handleEvent(event: Event) {}
342+
}
343+
`,
344+
);
345+
346+
const diags = env.driveDiagnostics();
347+
expect(diags.length).toBe(1);
348+
expect((diags[0].messageText as ts.DiagnosticMessageChain).messageText).toContain(
349+
`Argument of type 'AnimationCallbackEvent' is not assignable to parameter of type 'Event'.`,
350+
);
351+
expect(getDiagnosticSourceCode(diags[0])).toBe('$event');
352+
});
353+
304354
it('should not leak @let from the template into the host bindings', () => {
305355
env.write(
306356
'test.ts',

0 commit comments

Comments
 (0)