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
<span *ngIf="enabled && user as u">{{u.name}}</span>
```
2. Binding to `NgIfContext.$implicit` using the `let` syntax:
```html
<span *ngIf="enabled && user; let u">{{u.name}}</span>
```
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
This commit is contained in:
committed by
Misko Hevery
parent
cf4da82ac3
commit
9c8bc4a239
+1
-1
@@ -243,7 +243,7 @@ export declare class NgIf<T = unknown> {
|
||||
set ngIfThen(templateRef: TemplateRef<NgIfContext<T>> | null);
|
||||
constructor(_viewContainer: ViewContainerRef, templateRef: TemplateRef<NgIfContext<T>>);
|
||||
static ngTemplateGuard_ngIf: 'binding';
|
||||
static ngTemplateContextGuard<T>(dir: NgIf<T>, ctx: any): ctx is NgIfContext<NonNullable<T>>;
|
||||
static ngTemplateContextGuard<T>(dir: NgIf<T>, ctx: any): ctx is NgIfContext<Exclude<T, false | 0 | '' | null | undefined>>;
|
||||
}
|
||||
|
||||
export declare class NgIfContext<T = unknown> {
|
||||
|
||||
@@ -232,7 +232,8 @@ export class NgIf<T = unknown> {
|
||||
* 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<T>(dir: NgIf<T>, ctx: any): ctx is NgIfContext<NonNullable<T>> {
|
||||
static ngTemplateContextGuard<T>(dir: NgIf<T>, ctx: any):
|
||||
ctx is NgIfContext<Exclude<T, false|0|''|null|undefined>> {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ export declare class NgIf<T = unknown> {
|
||||
ngIfThen: TemplateRef<NgIfContext<T>> | null;
|
||||
constructor(_viewContainer: ViewContainerRef, templateRef: TemplateRef<NgIfContext<T>>);
|
||||
static ngTemplateGuard_ngIf: 'binding';
|
||||
static ngTemplateContextGuard<T>(dir: NgIf<T>, ctx: any): ctx is NgIfContext<NonNullable<T>>;
|
||||
static ngTemplateContextGuard<T>(dir: NgIf<T>, ctx: any): ctx is NgIfContext<Exclude<T, false | 0 | "" | null | undefined>>;
|
||||
static ɵdir: i0.ɵɵDirectiveDefWithMeta<NgIf<any>, '[ngIf]', never, {'ngIf': 'ngIf'}, {}, never>;
|
||||
}
|
||||
|
||||
@@ -818,7 +818,7 @@ export declare class AnimationEvent {
|
||||
template: '<div *ngIf="user; let u">{{u.name}}</div>',
|
||||
})
|
||||
class TestCmp {
|
||||
user: {name: string}|null;
|
||||
user: {name: string}|null|false;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
@@ -842,7 +842,7 @@ export declare class AnimationEvent {
|
||||
template: '<div *ngIf="user as u">{{u.name}}</div>',
|
||||
})
|
||||
class TestCmp {
|
||||
user: {name: string}|null;
|
||||
user: {name: string}|null|false;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
|
||||
Reference in New Issue
Block a user