@shencom/utils-tree
Version:
204 lines (200 loc) • 7.85 kB
TypeScript
/** 展开对象类型 */
type Unfurl<T> = T extends Record<string, unknown> ? { [K in keyof T]: T[K] } : T;
/** 递归移除 `readonly` */
type DeepMutable<T> = keyof T extends never
? T
: { -readonly [P in keyof T]: DeepMutable<T[P]> };
type Dictionary<T = any> = Record<string, T>;
interface TreeNodeOptions {
children?: string;
id?: string;
pid?: string;
}
interface TreeToArrayOptions {
children?: string;
keepChildren?: boolean;
}
type Flatten<T> = T extends any[] ? T[number] : T;
type AnyToArray<T> = T extends any[] ? T : T[];
type TreeType = Dictionary[] | Dictionary;
/**
* 树形数据平铺开转数组
*
* @template T
* @param {T} tree - 数据
* @param {TreeToArrayOptions} [options] - 配置属性
* @param {string} [options.children='children'] - 子节点映射字段
* @param {boolean} [options.keepChildren=false] - 是否保留完整子节点数据
* @example
* ```
* TreeToArray(tree);
* TreeToArray(tree, { children: 'child'});
* TreeToArray(tree, { children: 'child', keepChildren: true });
* ```
* @return {*} {AnyToArray<T>}
*/
declare function TreeToArray<T>(tree: T, options?: TreeToArrayOptions): AnyToArray<T>;
/**
* 查找树形数据中的某个节点
*
* @template T
* @param {T} tree - 数据
* @param {string} id - 节点 id
* @param {Omit<TreeNodeOptions, 'pid'>} [maps] - 配置属性
* @param {string} [maps.id='id'] - 节点 id 映射字段
* @param {string} [maps.children='children'] - 子节点映射字段
* @example
* ```
* TreeFindNode(tree, '1');
* TreeFindNode(tree, '1', { id: 'id1', children: 'child'});
* ```
* @return {*} {(Flatten<T> | null)}
*/
declare function TreeFindNode<T>(tree: T, id: string, maps?: Omit<TreeNodeOptions, 'pid'>): Flatten<T> | null;
/**
* 查找树形数据中的某个节点的所有父节点,返回数据中包含自身
*
* @template T
* @param {TreeType} tree - 数据
* @param {string} id - 节点 id
* @param {TreeNodeOptions} [maps] - 配置属性
* @param {string} [maps.id='id'] - 节点 id 映射字段
* @param {string} [maps.children='children'] - 子节点映射字段
* @param {string} [maps.pid='pid'] - 父节点 id 映射字段
* @param {boolean} [keepChildren=false] - 是否保留完整子节点数据
* @example
* ```
* TreeFindParentNodes(tree, '1');
* TreeFindParentNodes(tree, '1', { id: 'id', children: 'child', pid: 'pid'});
* TreeFindParentNodes(tree, '1', { id: 'id', children: 'child', pid: 'pid' }, true);
* ```
* @return {*} {T[]}
*/
declare function TreeFindParentNodes<T>(tree: T, id: string, maps?: TreeNodeOptions, keepChildren?: boolean): AnyToArray<T>;
/**
* 查找树形数据中的某个节点的所有父节点id
*
* @param {TreeType} tree - 数据
* @param {string} id - 节点 id
* @param {TreeNodeOptions} [maps] - 配置属性
* @param {string} [maps.id='id'] - 节点 id 映射字段
* @param {string} [maps.children='children'] - 子节点映射字段
* @param {string} [maps.pid='pid'] - 父节点 id 映射字段
* @example
* ```
* TreeFindParentIds(tree, '1');
* TreeFindParentIds(tree, '1', { id: 'id', children: 'child', pid: 'pid'});
* ```
* @return {*} {string[]}
*/
declare function TreeFindParentIds(tree: TreeType, id: string, maps?: TreeNodeOptions): string[];
interface ParentByKeyProps extends TreeNodeOptions {
key: string;
value: number | string;
}
/**
* 通过树形数据中的某个 key 的值,查找所有的父级节点,返回数据中包含自身
*
* @template T
* @param {T} tree - 数据
* @param {ParentByKeyProps} [props] - 配置属性
* @param {string} [props.key] - 要查找的 key
* @param {string | number} [props.value] - 要查找的 key 的值
* @param {string} [props.id='id'] - 节点 id 映射字段
* @param {string} [props.pid='pid'] - 父节点 id 映射字段
* @param {string} [props.children='children'] - 子节点映射字段
* @param {boolean} [keepChildren='false'] - 是否保留完整子节点数据
* @example
* ```
* TreeFindParentByKey(tree, { key: 'name', value: '1' });
* TreeFindParentByKey(tree, { key: 'name', value: '1', id: 'id', pid: 'pid', children: 'child' });
* TreeFindParentByKey(tree, { key: 'name', value: '1', id: 'id', pid: 'pid', children: 'child' }, true);
* ```
* @return {*} {T[]}
*/
declare function TreeFindParentByKey<T>(tree: T, props: ParentByKeyProps, keepChildren?: boolean): AnyToArray<T>;
interface TreeCallbackfn<T> {
(node: T): (T & {}) | Record<string, any>;
}
/**
* 处理树形结构每一项的数据
*
* @template T
* @param {T} tree - 数据
* @param {TreeCallbackfn<Flatten<T>>} handler - 处理函数
* @param {Pick<TreeNodeOptions, 'children'>} [maps] - 配置属性
* @param {string} [maps.children='children'] - 子节点映射字段
* @example
* ```
* TreeMap(tree, (node) => ({ ...node, title: node.name }));
* TreeMap(tree, (node) => ({ ...node, title: node.name }), { children: 'child'});
* ```
* @return {*} {AnyToArray<T>}
*/
declare function TreeMap<T>(tree: T, handler: TreeCallbackfn<Flatten<T>>, maps?: Pick<TreeNodeOptions, 'children'>): T;
/**
* 遍历树形结构每一项的数据
*
* @template T
* @param {T} tree - 数据
* @param {(node: T) => void} handler - 处理函数
* @param {Pick<TreeNodeOptions, 'children'>} [maps] - 配置属性
* @param {string} [maps.children='children'] - 子节点映射字段
* @example
* ```
* TreeForEach(tree, (node) => { ... });
* TreeForEach(tree, (node) => { ... }, { children: 'child'});
* ```
*/
declare function TreeForEach<T>(tree: T, handler: (node: T) => void, maps?: Pick<TreeNodeOptions, 'children'>): void;
type Pop<T extends any[]> = T extends [...infer P, any] ? P : [];
type MapToValue<MM extends Dictionary, TT extends any[], O = []> = TT['length'] extends 0 ? O : MapToValue<MM, Pop<TT>, {
[K in keyof MM as MM[K]]: TT[number][K] extends any[] ? MapToValue<MM, TT[number][K], TT[number][K][0]> extends never ? never : [MapToValue<MM, TT[number][K], TT[number][K][0]>] : TT[number][K];
}>;
/**
* 对树形结构中每一项的进行映射
*
* @template T
* @param {T} tree - 数据
* @param {Record<string, string>} maps - 映射关系
* @param {string} [childKey='children'] - 子节点字段
* @example
* ```
* TreeMapOption(tree, { title: 'name' });
* TreeMapOption(tree, { title: 'name' }, 'child');
* ```
* @return {*} {AnyToArray<T>}
*/
declare const TreeMapOption: <T extends TreeType, M extends Dictionary<(string & {}) | keyof Flatten<T>>, C extends string>(tree: T, maps: M, childKey?: C | undefined) => Unfurl<DeepMutable<MapToValue<M, AnyToArray<T>, []>>>;
/**
* 过滤树形结构中的每一项的数据
*
* @template T
* @param {T} tree - 数据
* @param {(node: T) => void} condition - 判断函数
* @param {Pick<TreeNodeOptions, 'children'>} [maps] - 配置属性
* @param {string} [maps.children='children'] - 子节点映射字段
* @example
* ```
* TreeFilter(tree, (node) => node.active);
* TreeFilter(tree, (node) => node.active, { children: 'child'});
* ```
* @return {*} {T}
*/
declare function TreeFilter<T>(tree: T, condition: (node: Flatten<T>) => boolean, maps?: Pick<TreeNodeOptions, 'children'>): T | null;
/**
* 将子节点列表为空数组处理成 null
*
* @template T
* @param {T} tree - 数据
* @param {Pick<TreeNodeOptions, 'children'>} [maps] - 配置属性
* @param {string} [maps.children='children'] - 子节点映射字段
* @example
* ```
* TreeFilterChildEmpty(tree);
* TreeFilterChildEmpty(tree, { children: 'child'});
* ```
* @return {*} {T}
*/
declare function TreeFilterChildEmpty<T>(tree: T, maps?: Pick<TreeNodeOptions, 'children'>): T;
export { TreeFilter, TreeFilterChildEmpty, TreeFindNode, TreeFindParentByKey, TreeFindParentIds, TreeFindParentNodes, TreeForEach, TreeMap, TreeMapOption, TreeToArray };