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
This commit is contained in:
Alex Rickabaugh 2018-10-03 10:57:46 -07:00 committed by Jason Aden
parent 868047e87f
commit 36d6e6076e
4 changed files with 24 additions and 1 deletions

View File

@ -198,6 +198,16 @@ export class NgForOf<T> implements DoCheck {
view: EmbeddedViewRef<NgForOfContext<T>>, record: IterableChangeRecord<any>) { view: EmbeddedViewRef<NgForOfContext<T>>, record: IterableChangeRecord<any>) {
view.context.$implicit = record.item; 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<T>(dir: NgForOf<T>, ctx: any): ctx is NgForOfContext<T> {
return true;
}
} }
class RecordViewTuple<T> { class RecordViewTuple<T> {

View File

@ -159,6 +159,16 @@ export class NgIf {
/** @internal */ /** @internal */
public static ngIfUseIfTypeGuard: void; 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<E>(dir: NgIf, expr: E): expr is NonNullable<E> { return true; }
} }
export class NgIfContext { export class NgIfContext {

View File

@ -101,7 +101,8 @@ class ToDoAppComponent {
// NON-NORMATIVE // NON-NORMATIVE
(ToDoAppComponent.ngComponentDef as r3.ComponentDef<any>).directiveDefs = () => (ToDoAppComponent.ngComponentDef as r3.ComponentDef<any>).directiveDefs = () =>
[ToDoItemComponent.ngComponentDef, (NgForOf as r3.DirectiveType<NgForOf<any>>).ngDirectiveDef]; [ToDoItemComponent.ngComponentDef,
(NgForOf as unknown as r3.DirectiveType<NgForOf<any>>).ngDirectiveDef];
// /NON-NORMATIVE // /NON-NORMATIVE
@Component({ @Component({

View File

@ -263,6 +263,7 @@ export declare class NgForOf<T> implements DoCheck {
ngForTrackBy: TrackByFunction<T>; ngForTrackBy: TrackByFunction<T>;
constructor(_viewContainer: ViewContainerRef, _template: TemplateRef<NgForOfContext<T>>, _differs: IterableDiffers); constructor(_viewContainer: ViewContainerRef, _template: TemplateRef<NgForOfContext<T>>, _differs: IterableDiffers);
ngDoCheck(): void; ngDoCheck(): void;
static ngTemplateContextGuard<T>(dir: NgForOf<T>, ctx: any): ctx is NgForOfContext<T>;
} }
export declare class NgForOfContext<T> { export declare class NgForOfContext<T> {
@ -282,6 +283,7 @@ export declare class NgIf {
ngIfElse: TemplateRef<NgIfContext> | null; ngIfElse: TemplateRef<NgIfContext> | null;
ngIfThen: TemplateRef<NgIfContext> | null; ngIfThen: TemplateRef<NgIfContext> | null;
constructor(_viewContainer: ViewContainerRef, templateRef: TemplateRef<NgIfContext>); constructor(_viewContainer: ViewContainerRef, templateRef: TemplateRef<NgIfContext>);
static ngTemplateGuard_ngIf<E>(dir: NgIf, expr: E): expr is NonNullable<E>;
} }
export declare class NgIfContext { export declare class NgIfContext {