fix(compiler-cli): set correct target when type checking events (#60561)

Currently the TCB generation code doesn't handle targeted events (e.g. `(document:click)`) which ends up binding to the current element and can have type inference implications. These changes take the event's `target` into account.

PR Close #60561
This commit is contained in:
Kristiyan Kostadinov
2025-03-26 10:50:53 +01:00
committed by Alex Rickabaugh
parent ec8c8f827e
commit 7e03af898e
2 changed files with 26 additions and 4 deletions
@@ -1578,11 +1578,19 @@ class TcbUnclaimedOutputsOp extends TcbOp {
// `$event` depending on the event name. For unknown event names, TypeScript resorts to the
// base `Event` type.
const handler = tcbCreateEventHandler(output, this.tcb, this.scope, EventParamType.Infer);
if (elId === null) {
elId = this.scope.resolve(this.target);
let target: ts.Expression;
// Only check for `window` and `document` since in theory any target can be passed.
if (output.target === 'window' || output.target === 'document') {
target = ts.factory.createIdentifier(output.target);
} else if (elId === null) {
target = elId = this.scope.resolve(this.target);
} else {
target = elId;
}
const propertyAccess = ts.factory.createPropertyAccessExpression(elId, 'addEventListener');
const propertyAccess = ts.factory.createPropertyAccessExpression(
target,
'addEventListener',
);
addParseSpanInfo(propertyAccess, output.keySpan);
const call = ts.factory.createCallExpression(
/* expression */ propertyAccess,
@@ -357,6 +357,20 @@ describe('type check blocks', () => {
);
});
it('should generate code for event targeting `window`', () => {
const block = tcb(`<button (window:scroll)="handle()"></button>`);
expect(block).toContain(
'window.addEventListener("scroll", ($event): any => { (this).handle(); });',
);
});
it('should generate code for event targeting `document`', () => {
const block = tcb(`<button (document:click)="handle()"></button>`);
expect(block).toContain(
'document.addEventListener("click", ($event): any => { (this).handle(); });',
);
});
it('should only generate directive declarations that have bindings or are referenced', () => {
const TEMPLATE = `
<div