Skip to content

Commit e05cfdd

Browse files
crisbetoatscott
authored andcommitted
fix(compiler-cli): incorrectly type checking calls to implicit template variables (#39686)
Currently when we encounter an implicit method call (e.g. `{{ foo(1) }}`) and we manage to resolve its receiver to something within the template, we assume that the method is on the receiver itself so we generate a type checking code to reflect it. This assumption is true in most cases, but it breaks down if the call is on an implicit receiver and the receiver itself is being invoked. E.g. ``` <div *ngFor="let fn of functions">{{ fn(1) }}</div> ``` These changes resolve the issue by generating a regular function call if the method call's receiver is pointing to `$implicit`. Fixes #39634. PR Close #39686
1 parent b363d96 commit e05cfdd

File tree

4 files changed

+33
-3
lines changed

4 files changed

+33
-3
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1609,7 +1609,7 @@ class TcbExpressionTranslator {
16091609
return null;
16101610
}
16111611

1612-
const method = ts.createPropertyAccess(wrapForDiagnostics(receiver), ast.name);
1612+
const method = wrapForDiagnostics(receiver);
16131613
addParseSpanInfo(method, ast.nameSpan);
16141614
const args = ast.args.map(arg => this.translate(arg));
16151615
const node = ts.createCall(method, undefined, args);

packages/compiler-cli/src/ngtsc/typecheck/test/span_comments_spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ describe('type check blocks diagnostics', () => {
7171
const TEMPLATE = `<ng-template let-method>{{ method(a, b) }}</ng-template>`;
7272
expect(tcbWithSpans(TEMPLATE))
7373
.toContain(
74-
'(_t2 /*27,39*/).method /*27,33*/(((ctx).a /*34,35*/) /*34,35*/, ((ctx).b /*37,38*/) /*37,38*/) /*27,39*/');
74+
'(_t2 /*27,39*/) /*27,33*/(((ctx).a /*34,35*/) /*34,35*/, ((ctx).b /*37,38*/) /*37,38*/) /*27,39*/');
7575
});
7676

7777
it('should annotate function calls', () => {

packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,20 @@ describe('type check blocks', () => {
106106
it('should handle method calls of template variables', () => {
107107
const TEMPLATE = `<ng-template let-a>{{a(1)}}</ng-template>`;
108108
expect(tcb(TEMPLATE)).toContain('var _t2 = _t1.$implicit;');
109-
expect(tcb(TEMPLATE)).toContain('(_t2).a(1)');
109+
expect(tcb(TEMPLATE)).toContain('(_t2)(1)');
110110
});
111111

112112
it('should handle implicit vars when using microsyntax', () => {
113113
const TEMPLATE = `<div *ngFor="let user of users"></div>`;
114114
expect(tcb(TEMPLATE)).toContain('var _t2 = _t1.$implicit;');
115115
});
116116

117+
it('should handle direct calls of an implicit template variable', () => {
118+
const TEMPLATE = `<div *ngFor="let a of letters">{{a(1)}}</div>`;
119+
expect(tcb(TEMPLATE)).toContain('var _t2 = _t1.$implicit;');
120+
expect(tcb(TEMPLATE)).toContain('(_t2)(1)');
121+
});
122+
117123
describe('type constructors', () => {
118124
it('should handle missing property bindings', () => {
119125
const TEMPLATE = `<div dir [inputA]="foo"></div>`;

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

+24
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,30 @@ export declare class AnimationEvent {
10091009
expect(diags.length).toBe(0);
10101010
});
10111011

1012+
it('should allow the implicit value of an NgFor to be invoked', () => {
1013+
env.tsconfig({fullTemplateTypeCheck: true, strictInputTypes: true});
1014+
env.write('test.ts', `
1015+
import {CommonModule} from '@angular/common';
1016+
import {Component, NgModule} from '@angular/core';
1017+
1018+
@Component({
1019+
selector: 'test',
1020+
template: '<div *ngFor="let fn of functions">{{fn()}}</div>',
1021+
})
1022+
class TestCmp {
1023+
functions = [() => 1, () => 2];
1024+
}
1025+
1026+
@NgModule({
1027+
declarations: [TestCmp],
1028+
imports: [CommonModule],
1029+
})
1030+
class Module {}
1031+
`);
1032+
1033+
env.driveMain();
1034+
});
1035+
10121036
it('should infer the context of NgIf', () => {
10131037
env.tsconfig({strictTemplates: true});
10141038
env.write('test.ts', `

0 commit comments

Comments
 (0)