Skip to content

Commit 9218140

Browse files
committed
fix(compiler-cli): resolve TCB mapping failure for safe property reads with as any
- Fixes TemplateSymbolBuilder.getTcbPositionForNode to recursively unwrap AsExpression and NonNullExpression nodes. - Added a test case in type_checker__get_symbol_of_template_node_spec.ts to verify symbol mapping when strictSafeNavigationTypes is false. - Note: The issue likely broke in commit 13c8df6.
1 parent 0a7f4dd commit 9218140

2 files changed

Lines changed: 37 additions & 0 deletions

File tree

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,10 @@ export class SymbolBuilder {
831831
return node.argumentExpression.getStart();
832832
} else if (ts.isCallExpression(node)) {
833833
return this.getTcbPositionForNode(node.expression);
834+
} else if (ts.isAsExpression(node)) {
835+
return this.getTcbPositionForNode(node.expression);
836+
} else if (ts.isNonNullExpression(node)) {
837+
return this.getTcbPositionForNode(node.expression);
834838
} else {
835839
return node.getStart();
836840
}

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
ParseTemplateOptions,
2929
TmplAstComponent,
3030
MatchSource,
31+
SafePropertyRead,
3132
} from '@angular/compiler';
3233
import ts from 'typescript';
3334

@@ -843,6 +844,38 @@ runInEachFileSystem(() => {
843844
).toEqual('string');
844845
});
845846

847+
it('safe property reads with as any (failure case)', () => {
848+
const fileName = absoluteFrom('/main.ts');
849+
const templateString = `<div [inputA]="route?.data?.icon"></div>`;
850+
const {templateTypeChecker, program} = setup(
851+
[
852+
{
853+
fileName,
854+
templates: {'Cmp': templateString},
855+
source: `
856+
interface Route {
857+
data: { icon: string; };
858+
}
859+
export class Cmp { route?: Route; }
860+
`,
861+
},
862+
],
863+
{strictSafeNavigationTypes: false},
864+
);
865+
const sf = getSourceFileOrError(program, fileName);
866+
const cmp = getClass(sf, 'Cmp');
867+
const nodes = getAstElements(templateTypeChecker, cmp);
868+
const ast = (nodes[0].inputs[0].value as ASTWithSource).ast as PropertyRead;
869+
const dataRead = ast.receiver as SafePropertyRead;
870+
const dataSymbol = templateTypeChecker.getSymbolOfNode(dataRead, cmp)!;
871+
assertExpressionSymbol(dataSymbol);
872+
expect(
873+
program
874+
.getTypeChecker()
875+
.symbolToString(templateTypeChecker.getTsSymbolOfSymbol(dataSymbol)!),
876+
).toEqual('data');
877+
});
878+
846879
it('ternary expressions', () => {
847880
const nodes = getAstElements(templateTypeChecker, cmp);
848881

0 commit comments

Comments
 (0)