From 36d6e6076e1feebce38aaede3fe4dd634a7f16e6 Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Wed, 3 Oct 2018 10:57:46 -0700 Subject: [PATCH] feat(ivy): support template type check narrowing for *ngFor and *ngIf (#26203) This commit adds an ngTemplateGuard_ngIf static method to the NgIf directive and an ngTemplateContextGuard static method to NgFor. The function of these two static methods is to enable type narrowing within generated type checking code for consumers of the directives. PR Close #26203 --- packages/common/src/directives/ng_for_of.ts | 10 ++++++++++ packages/common/src/directives/ng_if.ts | 10 ++++++++++ .../test/render3/compiler_canonical/small_app_spec.ts | 3 ++- tools/public_api_guard/common/common.d.ts | 2 ++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/common/src/directives/ng_for_of.ts b/packages/common/src/directives/ng_for_of.ts index b75b3f7d8d..1e21ac18f0 100644 --- a/packages/common/src/directives/ng_for_of.ts +++ b/packages/common/src/directives/ng_for_of.ts @@ -198,6 +198,16 @@ export class NgForOf implements DoCheck { view: EmbeddedViewRef>, record: IterableChangeRecord) { view.context.$implicit = record.item; } + + /** + * Assert the correct type of the context for the template that `NgForOf` will render. + * + * The presence of this method is a signal to the Ivy template type check compiler that the + * `NgForOf` structural directive renders its template with a specific context type. + */ + static ngTemplateContextGuard(dir: NgForOf, ctx: any): ctx is NgForOfContext { + return true; + } } class RecordViewTuple { diff --git a/packages/common/src/directives/ng_if.ts b/packages/common/src/directives/ng_if.ts index b9ea552b6f..3de5098c55 100644 --- a/packages/common/src/directives/ng_if.ts +++ b/packages/common/src/directives/ng_if.ts @@ -159,6 +159,16 @@ export class NgIf { /** @internal */ public static ngIfUseIfTypeGuard: void; + + /** + * Assert the correct type of the expression bound to the `ngIf` input within the template. + * + * The presence of this method is a signal to the Ivy template type check compiler that when the + * `NgIf` structural directive renders its template, the type of the expression bound to `ngIf` + * should be narrowed in some way. For `NgIf`, it is narrowed to be non-null, which allows the + * strictNullChecks feature of TypeScript to work with `NgIf`. + */ + static ngTemplateGuard_ngIf(dir: NgIf, expr: E): expr is NonNullable { return true; } } export class NgIfContext { diff --git a/packages/core/test/render3/compiler_canonical/small_app_spec.ts b/packages/core/test/render3/compiler_canonical/small_app_spec.ts index 0a98debf2c..94535dc182 100644 --- a/packages/core/test/render3/compiler_canonical/small_app_spec.ts +++ b/packages/core/test/render3/compiler_canonical/small_app_spec.ts @@ -101,7 +101,8 @@ class ToDoAppComponent { // NON-NORMATIVE (ToDoAppComponent.ngComponentDef as r3.ComponentDef).directiveDefs = () => - [ToDoItemComponent.ngComponentDef, (NgForOf as r3.DirectiveType>).ngDirectiveDef]; + [ToDoItemComponent.ngComponentDef, + (NgForOf as unknown as r3.DirectiveType>).ngDirectiveDef]; // /NON-NORMATIVE @Component({ diff --git a/tools/public_api_guard/common/common.d.ts b/tools/public_api_guard/common/common.d.ts index d5a18fd997..54709d66f5 100644 --- a/tools/public_api_guard/common/common.d.ts +++ b/tools/public_api_guard/common/common.d.ts @@ -263,6 +263,7 @@ export declare class NgForOf implements DoCheck { ngForTrackBy: TrackByFunction; constructor(_viewContainer: ViewContainerRef, _template: TemplateRef>, _differs: IterableDiffers); ngDoCheck(): void; + static ngTemplateContextGuard(dir: NgForOf, ctx: any): ctx is NgForOfContext; } export declare class NgForOfContext { @@ -282,6 +283,7 @@ export declare class NgIf { ngIfElse: TemplateRef | null; ngIfThen: TemplateRef | null; constructor(_viewContainer: ViewContainerRef, templateRef: TemplateRef); + static ngTemplateGuard_ngIf(dir: NgIf, expr: E): expr is NonNullable; } export declare class NgIfContext {