From 9c8bc4a2392b538b525352623458a541c7970a89 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Tue, 14 Apr 2020 19:55:39 +0200 Subject: [PATCH] fix(common): narrow `NgIf` context variables in template type checker (#36627) When the `NgIf` directive is used in a template, its context variables can be used to capture the bound value. This is sometimes used in complex expressions, where the resulting value is captured in a context variable. There's two syntax forms available: 1. Binding to `NgIfContext.ngIf` using the `as` syntax: ```html {{u.name}} ``` 2. Binding to `NgIfContext.$implicit` using the `let` syntax: ```html {{u.name}} ``` Because of the semantics of `ngIf`, it is known that the captured context variable is truthy, however the template type checker would not consider them as such and still report errors when `strict` is enabled. This commit updates `NgIf`'s context guard to make the types of the context variables truthy, avoiding the issue. Based on https://github.com/angular/angular/pull/35125 PR Close #36627 --- goldens/public-api/common/common.d.ts | 2 +- packages/common/src/directives/ng_if.ts | 3 ++- packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/goldens/public-api/common/common.d.ts b/goldens/public-api/common/common.d.ts index 8a6d5c0155..339f0b753d 100644 --- a/goldens/public-api/common/common.d.ts +++ b/goldens/public-api/common/common.d.ts @@ -243,7 +243,7 @@ export declare class NgIf { set ngIfThen(templateRef: TemplateRef> | null); constructor(_viewContainer: ViewContainerRef, templateRef: TemplateRef>); static ngTemplateGuard_ngIf: 'binding'; - static ngTemplateContextGuard(dir: NgIf, ctx: any): ctx is NgIfContext>; + static ngTemplateContextGuard(dir: NgIf, ctx: any): ctx is NgIfContext>; } export declare class NgIfContext { diff --git a/packages/common/src/directives/ng_if.ts b/packages/common/src/directives/ng_if.ts index e103313678..26704b8592 100644 --- a/packages/common/src/directives/ng_if.ts +++ b/packages/common/src/directives/ng_if.ts @@ -232,7 +232,8 @@ export class NgIf { * The presence of this method is a signal to the Ivy template type-check compiler that the * `NgIf` structural directive renders its template with a specific context type. */ - static ngTemplateContextGuard(dir: NgIf, ctx: any): ctx is NgIfContext> { + static ngTemplateContextGuard(dir: NgIf, ctx: any): + ctx is NgIfContext> { return true; } } diff --git a/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts b/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts index 6d084e5baa..377179e736 100644 --- a/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts +++ b/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts @@ -72,7 +72,7 @@ export declare class NgIf { ngIfThen: TemplateRef> | null; constructor(_viewContainer: ViewContainerRef, templateRef: TemplateRef>); static ngTemplateGuard_ngIf: 'binding'; - static ngTemplateContextGuard(dir: NgIf, ctx: any): ctx is NgIfContext>; + static ngTemplateContextGuard(dir: NgIf, ctx: any): ctx is NgIfContext>; static ɵdir: i0.ɵɵDirectiveDefWithMeta, '[ngIf]', never, {'ngIf': 'ngIf'}, {}, never>; } @@ -818,7 +818,7 @@ export declare class AnimationEvent { template: '
{{u.name}}
', }) class TestCmp { - user: {name: string}|null; + user: {name: string}|null|false; } @NgModule({ @@ -842,7 +842,7 @@ export declare class AnimationEvent { template: '
{{u.name}}
', }) class TestCmp { - user: {name: string}|null; + user: {name: string}|null|false; } @NgModule({