Skip to content

Commit caa8111

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 4136a70 commit caa8111

File tree

10 files changed

+37
-21
lines changed

10 files changed

+37
-21
lines changed

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

Lines changed: 2 additions & 2 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> {
@@ -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/nested-tree-control.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
import {Observable, isObservable} from 'rxjs';
99
import {take, filter} from 'rxjs/operators';
1010
import {BaseTreeControl} from './base-tree-control';
11+
import {GetChildrenFn} from './types';
1112

1213
/** Nested tree control. Able to expand/collapse a subtree recursively for NestedNode type. */
1314
export class NestedTreeControl<T> extends BaseTreeControl<T> {
1415

1516
/** Construct with nested tree function getChildren. */
16-
constructor(public getChildren: (dataNode: T) => (Observable<T[]> | T[] | undefined | null)) {
17+
constructor(public getChildren: GetChildrenFn<T>) {
1718
super();
1819
}
1920

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

Lines changed: 2 additions & 2 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.
@@ -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> {
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> {
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: 9 additions & 7 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> {
22
dataNodes: 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,8 +164,8 @@ export declare function getTreeMultipleDefaultNodeDefsError(): Error;
162164
export declare function getTreeNoValidDataSourceError(): Error;
163165

164166
export declare class NestedTreeControl<T> extends BaseTreeControl<T> {
165-
getChildren: (dataNode: T) => (Observable<T[]> | T[] | undefined | null);
166-
constructor(getChildren: (dataNode: T) => (Observable<T[]> | T[] | undefined | null));
167+
getChildren: GetChildrenFn<T>;
168+
constructor(getChildren: GetChildrenFn<T>);
167169
protected _getDescendants(descendants: T[], dataNode: T): void;
168170
expandAll(): void;
169171
getDescendants(dataNode: T): T[];
@@ -172,7 +174,7 @@ export declare class NestedTreeControl<T> extends BaseTreeControl<T> {
172174
export interface TreeControl<T, K = T> {
173175
dataNodes: T[];
174176
expansionModel: SelectionModel<K>;
175-
readonly getChildren: (dataNode: T) => Observable<T[]> | T[] | undefined | null;
177+
readonly getChildren: GetChildrenFn<T>;
176178
readonly getLevel: (dataNode: T) => number;
177179
readonly isExpandable: (dataNode: T) => boolean;
178180
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> extends DataSource<F> {
3333
}
3434

3535
export declare class MatTreeFlattener<T, 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>): F[];

0 commit comments

Comments
 (0)