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 {