diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts index 73608a6d4e..d1d08d50b0 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts @@ -1022,11 +1022,11 @@ export class Context { return ts.createIdentifier(`_t${this.nextId++}`); } - getPipeByName(name: string): ts.Expression|null { + getPipeByName(name: string): Reference>|null { if (!this.pipes.has(name)) { return null; } - return this.env.pipeInst(this.pipes.get(name)!); + return this.pipes.get(name)!; } } @@ -1568,19 +1568,20 @@ class TcbExpressionTranslator { return ts.createIdentifier('ctx'); } else if (ast instanceof BindingPipe) { const expr = this.translate(ast.exp); + const pipeRef = this.tcb.getPipeByName(ast.name); let pipe: ts.Expression|null; - if (this.tcb.env.config.checkTypeOfPipes) { - pipe = this.tcb.getPipeByName(ast.name); - if (pipe === null) { - // No pipe by that name exists in scope. Record this as an error. - this.tcb.oobRecorder.missingPipe(this.tcb.id, ast); + if (pipeRef === null) { + // No pipe by that name exists in scope. Record this as an error. + this.tcb.oobRecorder.missingPipe(this.tcb.id, ast); - // Return an 'any' value to at least allow the rest of the expression to be checked. - pipe = NULL_AS_ANY; - } + // Use an 'any' value to at least allow the rest of the expression to be checked. + pipe = NULL_AS_ANY; + } else if (this.tcb.env.config.checkTypeOfPipes) { + // Use a variable declared as the pipe's type. + pipe = this.tcb.env.pipeInst(pipeRef); } else { - pipe = ts.createParen(ts.createAsExpression( - ts.createNull(), ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword))); + // Use an 'any' value when not checking the type of the pipe. + pipe = NULL_AS_ANY; } const args = ast.args.map(arg => this.translate(arg)); const result = tsCallMethod(pipe, 'transform', [expr, ...args]); diff --git a/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts b/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts index 26212e3bc1..ae6db43321 100644 --- a/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts +++ b/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts @@ -1080,6 +1080,31 @@ export declare class AnimationEvent { expect(getSourceCodeForDiagnostic(diags[0])).toBe('unknown'); }); + it('should report an error with an unknown pipe even if `fullTemplateTypeCheck` is disabled', + () => { + env.tsconfig({ivyTemplateTypeCheck: true, fullTemplateTypeCheck: false}); + env.write('test.ts', ` + import {Component, NgModule} from '@angular/core'; + + @Component({ + selector: 'test', + template: '{{expr | unknown}}', + }) + class TestCmp { + expr = 3; + } + + @NgModule({ + declarations: [TestCmp], + }) + class Module {} + `); + const diags = env.driveDiagnostics(); + expect(diags.length).toBe(1); + expect(diags[0].messageText).toBe(`No pipe found with name 'unknown'.`); + expect(getSourceCodeForDiagnostic(diags[0])).toBe('unknown'); + }); + it('should report an error with pipe bindings', () => { env.write('test.ts', ` import {CommonModule} from '@angular/common';