feat(compiler): narrow types of expressions used in *ngIf (#20702)
Structural directives can now specify a type guard that describes what types can be inferred for an input expression inside the directive's template. NgIf was modified to declare an input guard on ngIf. After this change, `fullTemplateTypeCheck` will infer that usage of `ngIf` expression inside it's template is truthy. For example, if a component has a property `person?: Person` and a template of `<div *ngIf="person"> {{person.name}} </div>` the compiler will no longer report that `person` might be null or undefined. The template compiler will generate code similar to, ``` if (NgIf.ngIfTypeGuard(instance.person)) { instance.person.name } ``` to validate the template's use of the interpolation expression. Calling the type guard in this fashion allows TypeScript to infer that `person` is non-null. Fixes: #19756? PR Close #20702
This commit is contained in:

committed by
Jason Aden

parent
e544742156
commit
e7d9cb3e4c
@ -254,6 +254,7 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
|
||||
providers: CompileProviderMetadata[];
|
||||
viewProviders: CompileProviderMetadata[];
|
||||
queries: CompileQueryMetadata[];
|
||||
guards: {[key: string]: any};
|
||||
viewQueries: CompileQueryMetadata[];
|
||||
entryComponents: CompileEntryComponentMetadata[];
|
||||
changeDetection: ChangeDetectionStrategy|null;
|
||||
@ -268,8 +269,8 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
|
||||
*/
|
||||
export class CompileDirectiveMetadata {
|
||||
static create({isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs,
|
||||
host, providers, viewProviders, queries, viewQueries, entryComponents, template,
|
||||
componentViewType, rendererType, componentFactory}: {
|
||||
host, providers, viewProviders, queries, guards, viewQueries, entryComponents,
|
||||
template, componentViewType, rendererType, componentFactory}: {
|
||||
isHost: boolean,
|
||||
type: CompileTypeMetadata,
|
||||
isComponent: boolean,
|
||||
@ -282,6 +283,7 @@ export class CompileDirectiveMetadata {
|
||||
providers: CompileProviderMetadata[],
|
||||
viewProviders: CompileProviderMetadata[],
|
||||
queries: CompileQueryMetadata[],
|
||||
guards: {[key: string]: any};
|
||||
viewQueries: CompileQueryMetadata[],
|
||||
entryComponents: CompileEntryComponentMetadata[],
|
||||
template: CompileTemplateMetadata,
|
||||
@ -336,6 +338,7 @@ export class CompileDirectiveMetadata {
|
||||
providers,
|
||||
viewProviders,
|
||||
queries,
|
||||
guards,
|
||||
viewQueries,
|
||||
entryComponents,
|
||||
template,
|
||||
@ -358,6 +361,7 @@ export class CompileDirectiveMetadata {
|
||||
providers: CompileProviderMetadata[];
|
||||
viewProviders: CompileProviderMetadata[];
|
||||
queries: CompileQueryMetadata[];
|
||||
guards: {[key: string]: any};
|
||||
viewQueries: CompileQueryMetadata[];
|
||||
entryComponents: CompileEntryComponentMetadata[];
|
||||
|
||||
@ -367,10 +371,27 @@ export class CompileDirectiveMetadata {
|
||||
rendererType: StaticSymbol|object|null;
|
||||
componentFactory: StaticSymbol|object|null;
|
||||
|
||||
constructor({isHost, type, isComponent, selector, exportAs,
|
||||
changeDetection, inputs, outputs, hostListeners, hostProperties,
|
||||
hostAttributes, providers, viewProviders, queries, viewQueries,
|
||||
entryComponents, template, componentViewType, rendererType, componentFactory}: {
|
||||
constructor({isHost,
|
||||
type,
|
||||
isComponent,
|
||||
selector,
|
||||
exportAs,
|
||||
changeDetection,
|
||||
inputs,
|
||||
outputs,
|
||||
hostListeners,
|
||||
hostProperties,
|
||||
hostAttributes,
|
||||
providers,
|
||||
viewProviders,
|
||||
queries,
|
||||
guards,
|
||||
viewQueries,
|
||||
entryComponents,
|
||||
template,
|
||||
componentViewType,
|
||||
rendererType,
|
||||
componentFactory}: {
|
||||
isHost: boolean,
|
||||
type: CompileTypeMetadata,
|
||||
isComponent: boolean,
|
||||
@ -385,6 +406,7 @@ export class CompileDirectiveMetadata {
|
||||
providers: CompileProviderMetadata[],
|
||||
viewProviders: CompileProviderMetadata[],
|
||||
queries: CompileQueryMetadata[],
|
||||
guards: {[key: string]: any},
|
||||
viewQueries: CompileQueryMetadata[],
|
||||
entryComponents: CompileEntryComponentMetadata[],
|
||||
template: CompileTemplateMetadata|null,
|
||||
@ -406,6 +428,7 @@ export class CompileDirectiveMetadata {
|
||||
this.providers = _normalizeArray(providers);
|
||||
this.viewProviders = _normalizeArray(viewProviders);
|
||||
this.queries = _normalizeArray(queries);
|
||||
this.guards = guards;
|
||||
this.viewQueries = _normalizeArray(viewQueries);
|
||||
this.entryComponents = _normalizeArray(entryComponents);
|
||||
this.template = template;
|
||||
@ -430,6 +453,7 @@ export class CompileDirectiveMetadata {
|
||||
providers: this.providers,
|
||||
viewProviders: this.viewProviders,
|
||||
queries: this.queries,
|
||||
guards: this.guards,
|
||||
viewQueries: this.viewQueries,
|
||||
entryComponents: this.entryComponents,
|
||||
changeDetection: this.changeDetection,
|
||||
|
Reference in New Issue
Block a user