fix(common): expand type for "ngForOf" input to work with strict null checks (#31371)
Currently the `ngForOf` input accepts `null` or `undefined` as valid values. Although when using strict template input type checking (which will be supported by `ngtsc`), passing `null` or `undefined` with strict null checks enabled causes a type check failure because the type for the `ngForOf` input becomes too strict if strict null checks are enabled. The type of the input needs to be expanded to also accept `null` or `undefined` to behave consistently regardless of the `strictNullChecks` flag. This is necessary because whenever strict input type checking is enabled by default, most of the Angular projects that use `*ngFor` with the async pipe will either need to disable template type checking or strict null checks because the `async` pipe returns `null` if the observable hasn't been emitted yet. See for example how this affects the `angular/components` repository and how much bloat the workaround involves: https://github.com/angular/components/pull/16373/files#r296942696. PR Close #31371
This commit is contained in:

committed by
Alex Rickabaugh

parent
fee28e20bb
commit
c1bb88603e
@ -129,7 +129,7 @@ export class NgForOf<T> implements DoCheck {
|
||||
* [template input variable](guide/structural-directives#template-input-variable).
|
||||
*/
|
||||
@Input()
|
||||
set ngForOf(ngForOf: NgIterable<T>) {
|
||||
set ngForOf(ngForOf: NgIterable<T>|undefined|null) {
|
||||
this._ngForOf = ngForOf;
|
||||
this._ngForOfDirty = true;
|
||||
}
|
||||
@ -165,8 +165,7 @@ export class NgForOf<T> implements DoCheck {
|
||||
|
||||
get ngForTrackBy(): TrackByFunction<T> { return this._trackByFn; }
|
||||
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _ngForOf !: NgIterable<T>;
|
||||
private _ngForOf: NgIterable<T>|undefined|null = null;
|
||||
private _ngForOfDirty: boolean = true;
|
||||
private _differ: IterableDiffer<T>|null = null;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@ -219,8 +218,11 @@ export class NgForOf<T> implements DoCheck {
|
||||
(item: IterableChangeRecord<any>, adjustedPreviousIndex: number | null,
|
||||
currentIndex: number | null) => {
|
||||
if (item.previousIndex == null) {
|
||||
// NgForOf is never "null" or "undefined" here because the differ detected
|
||||
// that a new item needs to be inserted from the iterable. This implies that
|
||||
// there is an iterable value for "_ngForOf".
|
||||
const view = this._viewContainer.createEmbeddedView(
|
||||
this._template, new NgForOfContext<T>(null !, this._ngForOf, -1, -1),
|
||||
this._template, new NgForOfContext<T>(null !, this._ngForOf !, -1, -1),
|
||||
currentIndex === null ? undefined : currentIndex);
|
||||
const tuple = new RecordViewTuple<T>(item, view);
|
||||
insertTuples.push(tuple);
|
||||
@ -243,7 +245,7 @@ export class NgForOf<T> implements DoCheck {
|
||||
const viewRef = <EmbeddedViewRef<NgForOfContext<T>>>this._viewContainer.get(i);
|
||||
viewRef.context.index = i;
|
||||
viewRef.context.count = ilen;
|
||||
viewRef.context.ngForOf = this._ngForOf;
|
||||
viewRef.context.ngForOf = this._ngForOf !;
|
||||
}
|
||||
|
||||
changes.forEachIdentityChange((record: any) => {
|
||||
|
Reference in New Issue
Block a user