From 1ba5d2d5b908a05411b0a226eaed39070f4fec35 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Wed, 16 Oct 2019 16:04:34 +0200 Subject: [PATCH] fix(cdk/scrolling): expand type for "cdkVirtualForOf" input to work with strict null checks Currently the `cdkVirtualForOf` 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 definition of the input becomes too strict with "--strictNullChecks" enabled. For extra content: by default if strict null checks are not enabled, `null` or `undefined` are assignable to _every_ type. The current type definiton of the `cdkVirtualForOf` input is incorrectly making the assumption that `null` or `undefined` are always assignable. The type of the input needs to be expanded to explicitly accept `null` or `undefined` to behave consistently regardless of the `strictNullChecks` flag. A common scenario where this breaks is the use of `cdkVirtualFor` in combination with the async pipe from `@angular/common`. This is because the async pipe returns `null` until a value has been emitted. This means that with strict null checks, the type checking will fail because `null` is not allowed. This is similar to what we did for `ngFor` in framework: https://github.com/angular/angular/commit/c1bb886 Fixes #17411 --- src/cdk/scrolling/virtual-for-of.ts | 10 ++++++---- tools/public_api_guard/cdk/scrolling.d.ts | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/cdk/scrolling/virtual-for-of.ts b/src/cdk/scrolling/virtual-for-of.ts index d438c2524670..ed56e0bf499c 100644 --- a/src/cdk/scrolling/virtual-for-of.ts +++ b/src/cdk/scrolling/virtual-for-of.ts @@ -83,10 +83,10 @@ export class CdkVirtualForOf implements CollectionViewer, DoCheck, OnDestroy /** The DataSource to display. */ @Input() - get cdkVirtualForOf(): DataSource | Observable | NgIterable { + get cdkVirtualForOf(): DataSource | Observable | NgIterable | null | undefined { return this._cdkVirtualForOf; } - set cdkVirtualForOf(value: DataSource | Observable | NgIterable) { + set cdkVirtualForOf(value: DataSource | Observable | NgIterable | null | undefined) { this._cdkVirtualForOf = value; const ds = isDataSource(value) ? value : // Slice the value if its an NgIterable to ensure we're working with an array. @@ -94,7 +94,7 @@ export class CdkVirtualForOf implements CollectionViewer, DoCheck, OnDestroy value instanceof Observable ? value : Array.prototype.slice.call(value || [])); this._dataSourceChanges.next(ds); } - _cdkVirtualForOf: DataSource | Observable | NgIterable; + _cdkVirtualForOf: DataSource | Observable | NgIterable | null | undefined; /** * The `TrackByFunction` to use for tracking changes. The `TrackByFunction` takes the index and @@ -363,7 +363,9 @@ export class CdkVirtualForOf implements CollectionViewer, DoCheck, OnDestroy // comment node which can throw off the move when it's being repeated for all items. return this._viewContainerRef.createEmbeddedView(this._template, { $implicit: null!, - cdkVirtualForOf: this._cdkVirtualForOf, + // It's guaranteed that the iterable is not "undefined" or "null" because we only + // generate views for elements if the "cdkVirtualForOf" iterable has elements. + cdkVirtualForOf: this._cdkVirtualForOf!, index: -1, count: -1, first: false, diff --git a/tools/public_api_guard/cdk/scrolling.d.ts b/tools/public_api_guard/cdk/scrolling.d.ts index f47d94f7c1c4..3083a403640a 100644 --- a/tools/public_api_guard/cdk/scrolling.d.ts +++ b/tools/public_api_guard/cdk/scrolling.d.ts @@ -60,8 +60,8 @@ export declare class CdkScrollable implements OnInit, OnDestroy { } export declare class CdkVirtualForOf implements CollectionViewer, DoCheck, OnDestroy { - _cdkVirtualForOf: DataSource | Observable | NgIterable; - cdkVirtualForOf: DataSource | Observable | NgIterable; + _cdkVirtualForOf: DataSource | Observable | NgIterable | null | undefined; + cdkVirtualForOf: DataSource | Observable | NgIterable | null | undefined; cdkVirtualForTemplate: TemplateRef>; cdkVirtualForTemplateCacheSize: number; cdkVirtualForTrackBy: TrackByFunction | undefined;