Skip to content

Commit f7f3dac

Browse files
committed
fix(tree): allow readonly arrays in getChildren return type
Fixes not being allowed to return a `ReadonlyArray` from a `getChildren` function. Also pulls the definition for the `getChildren` function into a separate type so we don't have to maintain it in 4 different places. Fixes #17824.
1 parent 544e335 commit f7f3dac

File tree

11 files changed

+44
-28
lines changed

11 files changed

+44
-28
lines changed

src/cdk/tree/control/base-tree-control.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import {SelectionModel} from '@angular/cdk/collections';
9-
import {Observable} from 'rxjs';
109
import {TreeControl} from './tree-control';
10+
import {GetChildrenFn} from './types';
1111

1212
/** Base tree control. It has basic toggle/expand/collapse operations on a single data node. */
1313
export abstract class BaseTreeControl<T, K = T> implements TreeControl<T, K> {
@@ -19,7 +19,7 @@ export abstract class BaseTreeControl<T, K = T> implements TreeControl<T, K> {
1919
abstract expandAll(): void;
2020

2121
/** Saved data node for `expandAll` action. */
22-
dataNodes: T[];
22+
dataNodes: T[] | ReadonlyArray<T>;
2323

2424
/** A selection model with multi-selection to track expansion status. */
2525
expansionModel: SelectionModel<K> = new SelectionModel<K>(true);
@@ -42,7 +42,7 @@ export abstract class BaseTreeControl<T, K = T> implements TreeControl<T, K> {
4242
isExpandable: (dataNode: T) => boolean;
4343

4444
/** Gets a stream that emits whenever the given data node's children change. */
45-
getChildren: (dataNode: T) => (Observable<T[]> | T[] | undefined | null);
45+
getChildren: GetChildrenFn<T>;
4646

4747
/** Toggles one single data node's expanded/collapsed state. */
4848
toggle(dataNode: T): void {

src/cdk/tree/control/flat-tree-control.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,6 @@ export class FlatTreeControl<T, K = T> extends BaseTreeControl<T, K> {
5858
* data nodes of the tree.
5959
*/
6060
expandAll(): void {
61-
this.expansionModel.select(...this.dataNodes.map(node => this._trackByValue(node)));
61+
this.expansionModel.select(...(this.dataNodes as T[]).map(node => this._trackByValue(node)));
6262
}
6363
}

src/cdk/tree/control/nested-tree-control.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import {Observable, isObservable} from 'rxjs';
8+
import {isObservable} from 'rxjs';
99
import {take, filter} from 'rxjs/operators';
1010
import {BaseTreeControl} from './base-tree-control';
11+
import {GetChildrenFn} from './types';
1112

1213
/** Optional set of configuration that can be provided to the NestedTreeControl. */
1314
export interface NestedTreeControlOptions<T, K> {
@@ -18,7 +19,7 @@ export interface NestedTreeControlOptions<T, K> {
1819
export class NestedTreeControl<T, K = T> extends BaseTreeControl<T, K> {
1920
/** Construct with nested tree function getChildren. */
2021
constructor(
21-
public getChildren: (dataNode: T) => (Observable<T[]>| T[] | undefined | null),
22+
public getChildren: GetChildrenFn<T>,
2223
public options?: NestedTreeControlOptions<T, K>) {
2324
super();
2425

@@ -35,7 +36,7 @@ export class NestedTreeControl<T, K = T> extends BaseTreeControl<T, K> {
3536
*/
3637
expandAll(): void {
3738
this.expansionModel.clear();
38-
const allNodes = this.dataNodes.reduce((accumulator: T[], dataNode) =>
39+
const allNodes = (this.dataNodes as ReadonlyArray<T>).reduce((accumulator: T[], dataNode) =>
3940
[...accumulator, ...this.getDescendants(dataNode), dataNode], []);
4041
this.expansionModel.select(...allNodes.map(node => this._trackByValue(node)));
4142
}

src/cdk/tree/control/tree-control.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import {SelectionModel} from '@angular/cdk/collections';
9-
import {Observable} from 'rxjs';
9+
import {GetChildrenFn} from './types';
1010

1111
/**
1212
* Tree control interface. User can implement TreeControl to expand/collapse dataNodes in the tree.
@@ -15,7 +15,7 @@ import {Observable} from 'rxjs';
1515
*/
1616
export interface TreeControl<T, K = T> {
1717
/** The saved tree nodes data for `expandAll` action. */
18-
dataNodes: T[];
18+
dataNodes: T[] | ReadonlyArray<T>;
1919

2020
/** The expansion model */
2121
expansionModel: SelectionModel<K>;
@@ -60,5 +60,5 @@ export interface TreeControl<T, K = T> {
6060
readonly isExpandable: (dataNode: T) => boolean;
6161

6262
/** Gets a stream that emits whenever the given data node's children change. */
63-
readonly getChildren: (dataNode: T) => Observable<T[]> | T[] | undefined | null;
63+
readonly getChildren: GetChildrenFn<T>;
6464
}

src/cdk/tree/control/types.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Observable} from 'rxjs';
10+
11+
/** Function that can be used to get the children of a tree node. */
12+
export type GetChildrenFn<T> = (node: T) =>
13+
Observable<T[] | ReadonlyArray<T>> | T[] | ReadonlyArray<T> | undefined | null;

src/cdk/tree/nested-node.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export class CdkNestedTreeNode<T> extends CdkTreeNode<T> implements AfterContent
4646
private _dataDiffer: IterableDiffer<T>;
4747

4848
/** The children data dataNodes of current node. They will be placed in `CdkTreeNodeOutlet`. */
49-
protected _children: T[];
49+
protected _children: T[] | ReadonlyArray<T>;
5050

5151
/** The children node placeholder. */
5252
@ContentChildren(CdkTreeNodeOutlet, {
@@ -84,7 +84,7 @@ export class CdkNestedTreeNode<T> extends CdkTreeNode<T> implements AfterContent
8484
}
8585

8686
/** Add children dataNodes to the NodeOutlet */
87-
protected updateChildrenNodes(children?: T[]): void {
87+
protected updateChildrenNodes(children?: T[] | ReadonlyArray<T>): void {
8888
const outlet = this._getNodeOutlet();
8989
if (children) {
9090
this._children = children;

src/cdk/tree/public-api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export * from './control/base-tree-control';
1010
export * from './control/flat-tree-control';
1111
export * from './control/nested-tree-control';
1212
export * from './control/tree-control';
13+
export * from './control/types';
1314
export * from './nested-node';
1415
export * from './node';
1516
export * from './padding';

src/cdk/tree/tree.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ export class CdkTreeNode<T> implements FocusableOption, OnDestroy {
381381
}
382382
}
383383

384-
protected _setRoleFromChildren(children: T[]) {
384+
protected _setRoleFromChildren(children: T[] | ReadonlyArray<T>) {
385385
this.role = children && children.length ? 'group' : 'treeitem';
386386
}
387387
}

src/material/tree/data-source/flat-data-source.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import {CollectionViewer, DataSource} from '@angular/cdk/collections';
10-
import {FlatTreeControl, TreeControl} from '@angular/cdk/tree';
10+
import {FlatTreeControl, TreeControl, GetChildrenFn} from '@angular/cdk/tree';
1111
import {BehaviorSubject, merge, Observable} from 'rxjs';
1212
import {map, take} from 'rxjs/operators';
1313

@@ -50,8 +50,7 @@ export class MatTreeFlattener<T, F, K = F> {
5050
constructor(public transformFunction: (node: T, level: number) => F,
5151
public getLevel: (node: F) => number,
5252
public isExpandable: (node: F) => boolean,
53-
public getChildren: (node: T) =>
54-
Observable<T[]> | T[] | undefined | null) {}
53+
public getChildren: GetChildrenFn<T>) {}
5554

5655
_flattenNode(node: T, level: number,
5756
resultNodes: F[], parentMap: boolean[]): F[] {
@@ -64,7 +63,7 @@ export class MatTreeFlattener<T, F, K = F> {
6463
if (Array.isArray(childrenNodes)) {
6564
this._flattenChildren(childrenNodes, level, resultNodes, parentMap);
6665
} else {
67-
childrenNodes.pipe(take(1)).subscribe(children => {
66+
(childrenNodes as Observable<T[]>).pipe(take(1)).subscribe(children => {
6867
this._flattenChildren(children, level, resultNodes, parentMap);
6968
});
7069
}

tools/public_api_guard/cdk/tree.d.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export declare abstract class BaseTreeControl<T, K = T> implements TreeControl<T, K> {
2-
dataNodes: T[];
2+
dataNodes: T[] | ReadonlyArray<T>;
33
expansionModel: SelectionModel<K>;
4-
getChildren: (dataNode: T) => (Observable<T[]> | T[] | undefined | null);
4+
getChildren: GetChildrenFn<T>;
55
getLevel: (dataNode: T) => number;
66
isExpandable: (dataNode: T) => boolean;
77
trackBy?: (dataNode: T) => K;
@@ -21,7 +21,7 @@ export declare abstract class BaseTreeControl<T, K = T> implements TreeControl<T
2121
export declare const CDK_TREE_NODE_OUTLET_NODE: InjectionToken<{}>;
2222

2323
export declare class CdkNestedTreeNode<T> extends CdkTreeNode<T> implements AfterContentInit, OnDestroy {
24-
protected _children: T[];
24+
protected _children: T[] | ReadonlyArray<T>;
2525
protected _differs: IterableDiffers;
2626
protected _elementRef: ElementRef<HTMLElement>;
2727
protected _tree: CdkTree<T>;
@@ -30,7 +30,7 @@ export declare class CdkNestedTreeNode<T> extends CdkTreeNode<T> implements Afte
3030
protected _clear(): void;
3131
ngAfterContentInit(): void;
3232
ngOnDestroy(): void;
33-
protected updateChildrenNodes(children?: T[]): void;
33+
protected updateChildrenNodes(children?: T[] | ReadonlyArray<T>): void;
3434
static ɵdir: i0.ɵɵDirectiveDefWithMeta<CdkNestedTreeNode<any>, "cdk-nested-tree-node", ["cdkNestedTreeNode"], {}, {}, ["nodeOutlet"]>;
3535
static ɵfac: i0.ɵɵFactoryDef<CdkNestedTreeNode<any>, never>;
3636
}
@@ -74,7 +74,7 @@ export declare class CdkTreeNode<T> implements FocusableOption, OnDestroy {
7474
get level(): number;
7575
role: 'treeitem' | 'group';
7676
constructor(_elementRef: ElementRef<HTMLElement>, _tree: CdkTree<T>);
77-
protected _setRoleFromChildren(children: T[]): void;
77+
protected _setRoleFromChildren(children: T[] | ReadonlyArray<T>): void;
7878
protected _setRoleFromData(): void;
7979
focus(): void;
8080
ngOnDestroy(): void;
@@ -151,6 +151,8 @@ export interface FlatTreeControlOptions<T, K> {
151151
trackBy?: (dataNode: T) => K;
152152
}
153153

154+
export declare type GetChildrenFn<T> = (node: T) => Observable<T[] | ReadonlyArray<T>> | T[] | ReadonlyArray<T> | undefined | null;
155+
154156
export declare function getTreeControlFunctionsMissingError(): Error;
155157

156158
export declare function getTreeControlMissingError(): Error;
@@ -162,9 +164,9 @@ export declare function getTreeMultipleDefaultNodeDefsError(): Error;
162164
export declare function getTreeNoValidDataSourceError(): Error;
163165

164166
export declare class NestedTreeControl<T, K = T> extends BaseTreeControl<T, K> {
165-
getChildren: (dataNode: T) => (Observable<T[]> | T[] | undefined | null);
167+
getChildren: GetChildrenFn<T>;
166168
options?: NestedTreeControlOptions<T, K> | undefined;
167-
constructor(getChildren: (dataNode: T) => (Observable<T[]> | T[] | undefined | null), options?: NestedTreeControlOptions<T, K> | undefined);
169+
constructor(getChildren: GetChildrenFn<T>, options?: NestedTreeControlOptions<T, K> | undefined);
168170
protected _getDescendants(descendants: T[], dataNode: T): void;
169171
expandAll(): void;
170172
getDescendants(dataNode: T): T[];
@@ -175,9 +177,9 @@ export interface NestedTreeControlOptions<T, K> {
175177
}
176178

177179
export interface TreeControl<T, K = T> {
178-
dataNodes: T[];
180+
dataNodes: T[] | ReadonlyArray<T>;
179181
expansionModel: SelectionModel<K>;
180-
readonly getChildren: (dataNode: T) => Observable<T[]> | T[] | undefined | null;
182+
readonly getChildren: GetChildrenFn<T>;
181183
readonly getLevel: (dataNode: T) => number;
182184
readonly isExpandable: (dataNode: T) => boolean;
183185
collapse(dataNode: T): void;

tools/public_api_guard/material/tree.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ export declare class MatTreeFlatDataSource<T, F, K = F> extends DataSource<F> {
3333
}
3434

3535
export declare class MatTreeFlattener<T, F, K = F> {
36-
getChildren: (node: T) => Observable<T[]> | T[] | undefined | null;
36+
getChildren: GetChildrenFn<T>;
3737
getLevel: (node: F) => number;
3838
isExpandable: (node: F) => boolean;
3939
transformFunction: (node: T, level: number) => F;
40-
constructor(transformFunction: (node: T, level: number) => F, getLevel: (node: F) => number, isExpandable: (node: F) => boolean, getChildren: (node: T) => Observable<T[]> | T[] | undefined | null);
40+
constructor(transformFunction: (node: T, level: number) => F, getLevel: (node: F) => number, isExpandable: (node: F) => boolean, getChildren: GetChildrenFn<T>);
4141
_flattenChildren(children: T[], level: number, resultNodes: F[], parentMap: boolean[]): void;
4242
_flattenNode(node: T, level: number, resultNodes: F[], parentMap: boolean[]): F[];
4343
expandFlattenedNodes(nodes: F[], treeControl: TreeControl<F, K>): F[];

0 commit comments

Comments
 (0)