@suzilong/tree
v1.1.0
Published
功能全面的树操作库,提供树的遍历、搜索、修改等功能,适用于浏览器和node.js等环境。
Readme
tree
一个现代、轻量的 TS 树操作库,涵盖遍历(深度优先前序/后序、广度优先)、查找、转换、查询与修改等核心需求。纯函数设计确保数据不可变,支持自定义子节点字段,零依赖且类型完备,浏览器与 Node.js 均可使用。
特性
- 🚀 全面:涵盖树操作的常见场景
- 🔒 不可变:函数式编程,无副作用
- 🎯 灵活:支持自定义子节点字段名、遍历策略(DFS/BFS)和遍历顺序(前序,后序)
- 📦 轻量:无依赖,体积小巧(gzip后仅~3K),支持Tree-shaking
- 🌲 支持森林:可以处理多根节点的树(森林)
- 🛡️ 健壮:纯 TypeScript 编写,类型安全,测试用例覆盖全面
安装
npm i @suzilong/tree
# 或
yarn add @suzilong/tree
# 或
pnpm i @suzilong/tree使用示例
Es Module
import { forEach } from '@suzilong/tree'
forEach(tree, (node) => {
console.log(node)
})Node.js
const { forEach } = require('@suzilong/tree')
forEach(tree, (node) => {
console.log(node)
})直接在浏览器中使用
<script src="https://unpkg.com/@suzilong/tree"></script>
<script>
const { forEach } = window.Tree
forEach(tree, (node) => {
console.log(node)
})
</script>API 文档
目录
- 1. 遍历 (traverse)
- 2. 查找 (find)
- 3. 修改 (modify)
- 4. 转换 (transform)
- 5. 查询 (query)
- 6. 其他 (orther)
- 7. 关系判断 (is)
- 类型定义
1. 遍历 (traverse)
forEach
功能:对树中的每个节点执行一次给定的函数(无返回值,不中断)
参数:
tree: TreeNode | TreeNode[] - 树或森林callback: (node: TreeNode, context: Context) => void - 对每个节点执行的函数options: Options - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'strategy: 'dfs' | 'bfs' - 遍历策略,默认为 'dfs'(深度优先)order: 'pre' | 'post' - 仅在深度优先遍历时有效,默认为 'pre'(前序遍历)
示例:
import { forEach } from '@suzilong/tree'
const tree = {
id: '1',
children: [{ id: '1-1', children: [{ id: '1-1-1' }] }],
}
forEach(tree, (node, context) => {
console.log(`节点:${node.id}, 深度:${context.depth}`)
})
// 输出:节点:1, 深度:0
// 节点:1-1, 深度:1
// 节点:1-1-1, 深度:2depthFirst
功能:深度优先遍历树结构
参数:
tree: TreeNode | TreeNode[] - 树或森林callback: (node: TreeNode, context: Context) => boolean | void - 对每个节点执行的函数,返回 false 可中断遍历options: DepthFirstOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'order: 'pre' | 'post' - 遍历顺序,默认为 'pre'(前序遍历)
示例:
import { depthFirst } from '@suzilong/tree'
const tree = {
id: '1',
children: [{ id: '1-1', children: [{ id: '1-1-1' }] }],
}
// 前序遍历(默认)
depthFirst(tree, (node) => {
console.log(node.id)
})
// 输出:1, 1-1, 1-1-1breadthFirst
功能:广度优先遍历树结构
参数:
tree: TreeNode | TreeNode[] - 树或森林callback: (node: TreeNode, context: Context) => boolean | void - 对每个节点执行的函数,返回 false 可中断遍历options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
示例:
import { breadthFirst } from '@suzilong/tree'
const tree = {
id: '1',
children: [{ id: '1-1' }, { id: '1-2' }],
}
breadthFirst(tree, (node) => {
console.log(node.id)
})
// 输出:1, 1-1, 1-22. 查找 (find)
find
功能:在树结构中查找满足条件的节点
参数:
tree: TreeNode | TreeNode[] - 树或森林callback: (node: TreeNode) => boolean - 条件函数,返回 true 表示找到目标节点options: FindOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'strategy: 'dfs' | 'bfs' - 遍历策略,默认为 'dfs'order: 'pre' | 'post' - 仅在深度优先遍历时有效,默认为 'pre'
返回值:TreeNode | null - 满足条件的节点,如果未找到则返回 null
示例:
import { find } from '@suzilong/tree'
const tree = {
id: '1',
children: [{ id: '1-1' }, { id: '1-2' }],
}
const foundNode = find(tree, (node) => node.id === '1-2')
console.log(foundNode) // 输出:{ id: '1-2' }findAll
功能:在树结构中查找所有满足条件的节点
参数:
tree: TreeNode | TreeNode[] - 树或森林callback: (node: TreeNode) => boolean - 条件函数,返回 true 表示找到目标节点options: FindOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'strategy: 'dfs' | 'bfs' - 遍历策略,默认为 'dfs'order: 'pre' | 'post' - 仅在深度优先遍历时有效,默认为 'pre'
返回值:TreeNode[] - 满足条件的节点数组,如果未找到则返回空数组
示例:
import { findAll } from '@suzilong/tree'
const tree = {
id: '1',
type: 'parent',
children: [
{ id: '1-1', type: 'child' },
{ id: '1-2', type: 'child' },
],
}
const childNodes = findAll(tree, (node) => node.type === 'child')
console.log(childNodes.map((node) => node.id)) // 输出:['1-1', '1-2']findPath
功能:在树结构中查找满足条件的节点,并返回从根节点到该节点的路径
参数:
tree: TreeNode | TreeNode[] - 树或森林callback: (node: TreeNode) => boolean - 条件函数,返回 true 表示找到目标节点options: FindOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'strategy: 'dfs' | 'bfs' - 遍历策略,默认为 'dfs'order: 'pre' | 'post' - 仅在深度优先遍历时有效,默认为 'pre'
返回值:TreeNode[] - 根节点到该节点的路径,如果未找到则返回空数组
示例:
import { findPath } from '@suzilong/tree'
const tree = {
id: '1',
children: [{ id: '1-1', children: [{ id: '1-1-1' }] }],
}
const path = findPath(tree, (node) => node.id === '1-1-1')
console.log(path.map((node) => node.id)) // 输出:['1', '1-1', '1-1-1']3. 修改 (modify)
appendChild
功能:向指定父节点追加一个子节点(作为最后一个子节点),只操作第一个匹配的父节点
参数:
tree: TreeNode | TreeNode[] - 原树或森林predicate: (node: TreeNode) => boolean - 断言函数,用于定位父节点(只使用第一个匹配的节点)newNode: TreeNode - 要追加的新节点options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:TreeNode | TreeNode[] - 新树(如果未找到父节点,则返回原树)
示例:
import { appendChild } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }] }
const newTree = appendChild(tree, (node) => node.id === '1', { id: '1-2' })
console.log(newTree.children.map((node) => node.id)) // 输出:['1-1', '1-2']prependChild
功能:向指定父节点 prepend 一个子节点(作为第一个子节点),只操作第一个匹配的父节点
参数:
tree: TreeNode | TreeNode[] - 原树或森林predicate: (node: TreeNode) => boolean - 断言函数,用于定位父节点(只使用第一个匹配的节点)newNode: TreeNode - 要 prepend 的新节点options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:TreeNode | TreeNode[] - 新树(如果未找到父节点,则返回原树)
示例:
import { prependChild } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }] }
const newTree = prependChild(tree, (node) => node.id === '1', { id: '1-0' })
console.log(newTree.children.map((node) => node.id)) // 输出:['1-0', '1-1']insertBefore
功能:在指定节点前插入一个新节点,只操作第一个匹配的目标节点
参数:
tree: TreeNode | TreeNode[] - 原树或森林predicate: (node: TreeNode) => boolean - 断言函数,用于定位目标节点(只使用第一个匹配的节点)newNode: TreeNode - 要插入的新节点options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:TreeNode | TreeNode[] - 新树(如果未找到目标节点,则返回原树)
示例:
import { insertBefore } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const newTree = insertBefore(tree, (node) => node.id === '1-2', { id: '1-1.5' })
console.log(newTree.children.map((node) => node.id)) // 输出:['1-1', '1-1.5', '1-2']insertAfter
功能:在指定节点后插入一个新节点,只操作第一个匹配的目标节点
参数:
tree: TreeNode | TreeNode[] - 原树或森林predicate: (node: TreeNode) => boolean - 断言函数,用于定位目标节点(只使用第一个匹配的节点)newNode: TreeNode - 要插入的新节点options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:TreeNode | TreeNode[] - 新树(如果未找到目标节点,则返回原树)
示例:
import { insertAfter } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const newTree = insertAfter(tree, (node) => node.id === '1-1', { id: '1-1.5' })
console.log(newTree.children.map((node) => node.id)) // 输出:['1-1', '1-1.5', '1-2']remove
功能:移除树中所有满足条件的节点
参数:
tree: TreeNode | TreeNode[] - 原树或森林predicate: (node: TreeNode) => boolean - 断言函数,用于定位要移除的节点options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:null | TreeNode | TreeNode[] - 新树(如果未找到要移除的节点,则返回原树)
示例:
import { remove } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const newTree = remove(tree, (node) => node.id === '1-1')
console.log(newTree.children.map((node) => node.id)) // 输出:['1-2']replace
功能:替换树中所有满足条件的节点
参数:
tree: TreeNode | TreeNode[] - 原树或森林predicate: (node: TreeNode) => boolean - 断言函数,用于定位要替换的节点newNode: TreeNode - 新节点options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:TreeNode | TreeNode[] - 新树(如果未找到要替换的节点,则返回原树)
示例:
import { replace } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const newTree = replace(tree, (node) => node.id === '1-1', { id: '1-1-new' })
console.log(newTree.children.map((node) => node.id)) // 输出:['1-1-new', '1-2']move
功能:将一个节点移动到另一个节点的子节点列表中(作为最后一个子节点),只操作第一个匹配的源节点和目标节点
参数:
tree: TreeNode | TreeNode[] - 原树或森林sourcePredicate: (node: TreeNode) => boolean - 断言函数,用于定位要移动的节点(只使用第一个匹配的节点)targetPredicate: (node: TreeNode) => boolean - 断言函数,用于定位目标父节点(只使用第一个匹配的节点)options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:TreeNode | TreeNode[] - 新树(如果未找到源节点或目标节点,则返回原树)
示例:
import { move } from '@suzilong/tree'
const tree = {
id: '1',
children: [{ id: '1-1' }, { id: '1-2', children: [] }],
}
const newTree = move(
tree,
(node) => node.id === '1-1',
(node) => node.id === '1-2'
)
console.log(newTree.children[0].children.map((node) => node.id)) // 输出:['1-1']swap
功能:交换树中两个节点的位置,只操作第一个匹配的节点
参数:
tree: TreeNode | TreeNode[] - 原树或森林predicate1: (node: TreeNode) => boolean - 断言函数,用于定位第一个节点predicate2: (node: TreeNode) => boolean - 断言函数,用于定位第二个节点options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:TreeNode | TreeNode[] - 新树(如果未找到节点或无法交换,则返回原树)
示例:
import { swap } from '@suzilong/tree'
const tree = {
id: '1',
children: [
{ id: 'A', value: 1 },
{ id: 'B', value: 2 },
],
}
const newTree = swap(
tree,
(node) => node.id === 'A',
(node) => node.id === 'B'
)
console.log(newTree.children.map((node) => node.value)) // 输出:[2, 1]4. 转换 (transform)
arrayToTree
功能:将扁平数组转换为树结构
参数:
array: any[] - 扁平数组options: ArrayToTreeOptions - 配置选项idKey: string - 节点唯一标识字段名,默认为 'id'parentIdKey: string - 父节点标识字段名,默认为 'parentId'childrenKey: string - 子节点数组字段名,默认为 'children'rootParentValue: null | undefined | string | number - 根节点的父标识值,默认为 null 或 undefined
返回值:TreeNode[] - 转换后的树结构(森林)
示例:
import { arrayToTree } from '@suzilong/tree'
const array = [
{ id: '1', name: '节点1', parentId: null },
{ id: '2', name: '节点2', parentId: '1' },
{ id: '3', name: '节点3', parentId: '1' },
{ id: '4', name: '节点4', parentId: '2' },
]
const tree = arrayToTree(array)
console.log(tree[0].id) // 输出: '1'
console.log(tree[0].children.length) // 输出: 2
console.log(tree[0].children[0].children[0].id) // 输出: '4'treeToArray
功能:将树结构转换为扁平数组
参数:
tree: TreeNode | TreeNode[] - 树或森林options: TreeToArrayOptions - 配置选项idKey: string - 节点唯一标识字段名,默认为 'id'parentIdKey: string - 输出中父节点标识字段名,默认为 'parentId'childrenKey: string - 自定义子节点字段名,默认为 'children'rootParentValue: null | undefined | string | number - 根节点的父标识值,默认为 nullkeepChildren: boolean - 是否在输出中保留子节点数组,默认为 false(移除 children)strategy: 'dfs' | 'bfs' - 遍历策略,默认为 'dfs'order: 'pre' | 'post' - 遍历顺序,仅对 dfs 有效,默认为 'pre'
返回值:any[] - 转换后的扁平数组
示例:
import { treeToArray } from '@suzilong/tree'
const tree = [{ id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }]
const array = treeToArray(tree)
console.log(array.map((item) => item.id)) // 输出:['1', '1-1', '1-2']map
功能:对树中的每个节点执行映射函数,返回新树
参数:
tree: TreeNode | TreeNode[] - 树或森林callback: (node: TreeNode, context: Context) => TreeNode - 映射函数,返回新节点options: Options - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'strategy: 'dfs' | 'bfs' - 遍历策略,默认为 'dfs'order: 'pre' | 'post' - 仅在深度优先遍历时有效,默认为 'pre'
返回值:TreeNode | TreeNode[] - 映射后的新树
示例:
import { map } from '@suzilong/tree'
const tree = { id: '1', value: 10, children: [{ id: '1-1', value: 20 }] }
const newTree = map(tree, (node) => ({
...node,
value: node.value * 2,
}))
console.log(newTree.value) // 输出:20filter
功能:过滤树中的节点,返回新树
参数:
tree: TreeNode | TreeNode[] - 树或森林callback: (node: TreeNode, context: Context) => boolean - 过滤函数,返回 true 表示保留节点options: Options - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'strategy: 'dfs' | 'bfs' - 遍历策略,默认为 'dfs'order: 'pre' | 'post' - 仅在深度优先遍历时有效,默认为 'pre'
返回值:TreeNode | TreeNode[] - 过滤后的新树
示例:
import { filter } from '@suzilong/tree'
const tree = {
id: '1',
type: 'parent',
children: [
{ id: '1-1', type: 'child' },
{ id: '1-2', type: 'parent' },
],
}
const filteredTree = filter(tree, (node) => node.type === 'parent')
console.log(filteredTree.children.length) // 输出:1reduce
功能:对树中的节点执行归约函数,返回累加结果
参数:
tree: TreeNode | TreeNode[] - 树或森林callback: (accumulator: any, node: TreeNode, context: Context) => any - 归约函数initialValue: any - 初始累加值options: Options - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'strategy: 'dfs' | 'bfs' - 遍历策略,默认为 'dfs'order: 'pre' | 'post' - 仅在深度优先遍历时有效,默认为 'pre'
返回值:any - 归约结果
示例:
import { reduce } from '@suzilong/tree'
const tree = { id: '1', value: 10, children: [{ id: '1-1', value: 20 }] }
const sum = reduce(tree, (acc, node) => acc + node.value, 0)
console.log(sum) // 输出:30flat
功能:将树结构扁平化为节点数组
参数:
tree: TreeNode | TreeNode[] - 树或森林options: Options - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'strategy: 'dfs' | 'bfs' - 遍历策略,默认为 'dfs'order: 'pre' | 'post' - 仅在深度优先遍历时有效,默认为 'pre'
返回值:TreeNode[] - 扁平后的节点数组
示例:
import { flat } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const nodes = flat(tree)
console.log(nodes.map((node) => node.id)) // 输出:['1', '1-1', '1-2']5. 查询 (query)
getCount
功能:获取树中节点的数量
参数:
tree: TreeNode | TreeNode[] - 树或森林options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:number - 节点数量
示例:
import { getCount } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const count = getCount(tree)
console.log(count) // 输出:3getLeafCount
功能:获取树中叶子节点的数量
参数:
tree: TreeNode | TreeNode[] - 树或森林options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:number - 叶子节点数量
示例:
import { getLeafCount } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const leafCount = getLeafCount(tree)
console.log(leafCount) // 输出:2getDepth
功能:获取树的深度
参数:
tree: TreeNode | TreeNode[] - 树或森林options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:number - 树的深度
示例:
import { getDepth } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const depth = getDepth(tree)
console.log(depth) // 输出:2getAncestors
功能:获取指定节点的所有祖先节点
参数:
tree: TreeNode | TreeNode[] - 树或森林predicate: (node: TreeNode) => boolean - 断言函数,用于定位目标节点options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:TreeNode[] - 祖先节点数组(从根节点到父节点)
示例:
import { getAncestors } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const ancestors = getAncestors(tree, (node) => node.id === '1-1')
console.log(ancestors.map((node) => node.id)) // 输出:['1']getDescendants
功能:获取指定节点的所有后代节点
参数:
tree: TreeNode | TreeNode[] - 树或森林predicate: (node: TreeNode) => boolean - 断言函数,用于定位目标节点options: Options - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'strategy: 'dfs' | 'bfs' - 遍历策略,默认为 'dfs'order: 'pre' | 'post' - 仅在深度优先遍历时有效,默认为 'pre'
返回值:TreeNode[] - 后代节点数组
示例:
import { getDescendants } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const descendants = getDescendants(tree, (node) => node.id === '1')
console.log(descendants.map((node) => node.id)) // 输出:['1-1', '1-2']getSiblings
功能:获取指定节点的所有兄弟节点(不包括自身)
参数:
tree: TreeNode | TreeNode[] - 树或森林predicate: (node: TreeNode) => boolean - 断言函数,用于定位目标节点options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:TreeNode[] - 兄弟节点数组
示例:
import { getSiblings } from '@suzilong/tree'
const tree = {
id: '1',
children: [{ id: '1-1' }, { id: '1-2' }, { id: '1-3' }],
}
const siblings = getSiblings(tree, (node) => node.id === '1-2')
console.log(siblings.map((node) => node.id)) // 输出:['1-1', '1-3']getParent
功能:获取指定节点的父节点
参数:
tree: TreeNode | TreeNode[] - 树或森林predicate: (node: TreeNode) => boolean - 断言函数,用于定位目标节点options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:TreeNode | null - 父节点,如果目标不存在或是根节点则返回 null
示例:
import { getParent } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const parent = getParent(tree, (node) => node.id === '1-1')
console.log(parent?.id) // 输出:'1'getChildren
功能:获取指定节点的所有子节点
参数:
tree: TreeNode | TreeNode[] - 树或森林predicate: (node: TreeNode) => boolean - 断言函数,用于定位目标节点options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:TreeNode[] - 子节点数组,如果目标不存在或没有子节点则返回空数组
示例:
import { getChildren } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const children = getChildren(tree, (node) => node.id === '1')
console.log(children.map((node) => node.id)) // 输出:['1-1', '1-2']6. 其他 (orther)
clone
功能:深拷贝树结构
参数:
tree: TreeNode | TreeNode[] - 树或森林options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:TreeNode | TreeNode[] - 拷贝后的新树
示例:
import { clone } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }] }
const clonedTree = clone(tree)
console.log(clonedTree !== tree && clonedTree.children !== tree.children) // 输出:trueevery
功能:检查树中的所有节点是否都满足条件
参数:
tree: TreeNode | TreeNode[] - 树或森林callback: (node: TreeNode, context: Context) => boolean - 条件函数options: Options - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'strategy: 'dfs' | 'bfs' - 遍历策略,默认为 'dfs'order: 'pre' | 'post' - 仅在深度优先遍历时有效,默认为 'pre'
返回值:boolean - 所有节点都满足条件返回 true,否则返回 false
示例:
import { every } from '@suzilong/tree'
const tree = { id: '1', type: 'node', children: [{ id: '1-1', type: 'node' }] }
const allNodes = every(tree, (node) => node.type === 'node')
console.log(allNodes) // 输出:truesome
功能:检查树中是否至少有一个节点满足条件
参数:
tree: TreeNode | TreeNode[] - 树或森林callback: (node: TreeNode, context: Context) => boolean - 条件函数options: Options - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'strategy: 'dfs' | 'bfs' - 遍历策略,默认为 'dfs'order: 'pre' | 'post' - 仅在深度优先遍历时有效,默认为 'pre'
返回值:boolean - 至少有一个节点满足条件返回 true,否则返回 false
示例:
import { some } from '@suzilong/tree'
const tree = {
id: '1',
type: 'parent',
children: [{ id: '1-1', type: 'child' }],
}
const hasChild = some(tree, (node) => node.type === 'child')
console.log(hasChild) // 输出:true功能:在控制台打印tree,用于调试,打印结果类似Linux tree命令
参数:
tree: TreeNode | TreeNode[] - 树或森林options: Options - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:无
示例:
import { print } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }] }
print(tree)
// 输出:
// └── 1
// └── 1-17. 关系判断 (is)
isSibling
功能:判断两个节点是否为兄弟节点(即具有相同的父节点)
参数:
tree: TreeNode | TreeNode[] - 树或森林predicateA: (node: TreeNode) => boolean - 定位第一个节点的断言函数predicateB: (node: TreeNode) => boolean - 定位第二个节点的断言函数options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:boolean - 是兄弟则返回 true,否则 false
示例:
import { isSibling } from '@suzilong/tree'
const tree = {
id: '1',
children: [{ id: '2' }, { id: '3' }, { id: '4' }],
}
const areBrothers = isSibling(
tree,
(node) => node.id === 2,
(node) => node.id === 3
)
console.log(areBrothers) // 输出:trueisAncestorOf
功能:判断 ancestor 节点是否是 descendant 节点的祖先(即 ancestor 在从根节点到 descendant 的路径上)
参数:
tree: TreeNode | TreeNode[] - 树或森林ancestorPredicate: (node: TreeNode) => boolean - 定位祖先节点的断言函数descendantPredicate: (node: TreeNode) => boolean - 定位后代节点的断言函数options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:boolean - 是祖先关系则返回 true,否则 false
示例:
import { isAncestorOf } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1', children: [{ id: '1-1-1' }] }] }
const isRootAncestor = isAncestorOf(
tree,
(node) => node.id === '1',
(node) => node.id === '1-1-1'
)
console.log(isRootAncestor) // 输出:trueisDescendantOf
功能:判断 descendant 节点是否是 ancestor 节点的后代(即 descendant 在 ancestor 的子树中)
参数:
tree: TreeNode | TreeNode[] - 树或森林descendantPredicate: (node: TreeNode) => boolean - 定位后代节点的断言函数ancestorPredicate: (node: TreeNode) => boolean - 定位祖先节点的断言函数options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:boolean - 是后代关系则返回 true,否则 false
示例:
import { isDescendantOf } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1', children: [{ id: '1-1-1' }] }] }
const isLeafDescendant = isDescendantOf(
tree,
(node) => node.id === '1-1-1',
(node) => node.id === '1'
)
console.log(isLeafDescendant) // 输出:trueisParentOf
功能:判断 parent 节点是否是 child 节点的直接父节点
参数:
tree: TreeNode | TreeNode[] - 树或森林parentPredicate: (node: TreeNode) => boolean - 定位父节点的断言函数childPredicate: (node: TreeNode) => boolean - 定位子节点的断言函数options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:boolean - 是直接父子关系则返回 true,否则 false
示例:
import { isParentOf } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1', children: [{ id: '1-1-1' }] }] }
const isDirectParent = isParentOf(
tree,
(node) => node.id === '1',
(node) => node.id === '1-1'
)
console.log(isDirectParent) // 输出:trueisChildOf
功能:判断 child 节点是否是 parent 节点的直接子节点
参数:
tree: TreeNode | TreeNode[] - 树或森林childPredicate: (node: TreeNode) => boolean - 定位子节点的断言函数parentPredicate: (node: TreeNode) => boolean - 定位父节点的断言函数options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:boolean - 是直接父子关系则返回 true,否则 false
示例:
import { isChildOf } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1', children: [{ id: '1-1-1' }] }] }
const isDirectChild = isChildOf(
tree,
(node) => node.id === '1-1',
(node) => node.id === '1'
)
console.log(isDirectChild) // 输出:trueisRoot
功能:判断节点是否为根节点(即没有父节点)
参数:
tree: TreeNode | TreeNode[] - 树或森林predicate: (node: TreeNode) => boolean - 定位节点的断言函数options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:boolean - 是根节点则返回 true,否则 false
示例:
import { isRoot } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }] }
const isRootNode = isRoot(tree, (node) => node.id === '1')
console.log(isRootNode) // 输出:trueisLeaf
功能:判断节点是否为叶子节点(即没有子节点)
参数:
tree: TreeNode | TreeNode[] - 树或森林predicate: (node: TreeNode) => boolean - 定位节点的断言函数options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:boolean - 是叶子节点则返回 true,否则 false
示例:
import { isLeaf } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }] }
const isLeafNode = isLeaf(tree, (node) => node.id === '1-1')
console.log(isLeafNode) // 输出:trueisSameDepth
功能:判断两个节点是否在同一深度(即同一层)
参数:
tree: TreeNode | TreeNode[] - 树或森林predicateA: (node: TreeNode) => boolean - 定位第一个节点的断言函数predicateB: (node: TreeNode) => boolean - 定位第二个节点的断言函数options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:boolean - 如果两个节点深度相同则返回 true,否则 false
示例:
import { isSameDepth } from '@suzilong/tree'
const tree = { id: '1', children: [{ id: '1-1' }, { id: '1-2' }] }
const sameDepth = isSameDepth(
tree,
(node) => node.id === '1-1',
(node) => node.id === '1-2'
)
console.log(sameDepth) // 输出:trueisEqual
功能:比较两棵树是否相等(通过自定义比较函数)
参数:
tree1: TreeNode | TreeNode[] - 第一棵树或森林tree2: TreeNode | TreeNode[] - 第二棵树或森林compare: (node1: TreeNode, node2: TreeNode) => boolean - 节点比较函数options: BaseOptions - 配置选项childrenKey: string - 自定义子节点字段名,默认为 'children'
返回值:boolean - 如果两棵树结构相同且所有对应节点都满足比较函数则返回 true,否则 false
示例:
import { isEqual } from '@suzilong/tree'
const tree1 = { id: '1', children: [{ id: '1-1', value: 10 }] }
const tree2 = { id: '1', children: [{ id: '1-1', value: 99 }] }
const equalById = isEqual(tree1, tree2, (n1, n2) => n1.id === n2.id)
console.log(equalById) // 输出:true类型定义
TreeNode
type TreeNode<T = unknown, ChildKey extends string = 'children'> = {
[key: string]: unknown // 允许任意其他属性
} & {
[K in ChildKey]?: TreeNode<T, ChildKey>[] // 动态子节点字段
}Context
interface Context {
index: number // 当前节点在兄弟节点中的位置(从 0 开始)
depth: number // 当前节点深度(根节点为 0)
parent: TreeNode | null // 父节点,根节点为 null
path: TreeNode[] // 从根到当前节点的路径
}Options
interface Options extends BaseOptions {
strategy?: 'dfs' | 'bfs' // 遍历策略,默认为 'dfs'(深度优先),可选 'bfs'(广度优先)
order?: 'pre' | 'post' // 仅在深度优先遍历时有效,默认为 'pre'(前序遍历),可选 'post'(后序遍历)
}BaseOptions
interface BaseOptions {
childrenKey?: string // 自定义子节点字段名,默认为 'children'
}ArrayToTreeOptions
interface ArrayToTreeOptions {
/** 节点唯一标识字段名,默认为 'id' */
idKey?: string
/** 父节点标识字段名,默认为 'parentId' */
parentIdKey?: string
/** 子节点数组字段名,默认为 'children' */
childrenKey?: string
/** 根节点的父标识值,默认为 null 或 undefined */
rootParentValue?: null | undefined | string | number
}TreeToArrayOptions
interface TreeToArrayOptions {
/** 节点唯一标识字段名,默认为 'id' */
idKey?: string
/** 输出中父节点标识字段名,默认为 'parentId' */
parentIdKey?: string
/** 自定义子节点字段名,默认为 'children' */
childrenKey?: string
/** 根节点的父标识值,默认为 null */
rootParentValue?: null | undefined | string | number
/** 是否在输出中保留子节点数组,默认为 false(移除 children) */
keepChildren?: boolean
/** 遍历策略,默认为 'dfs' */
strategy?: 'dfs' | 'bfs'
/** 遍历顺序,仅对 dfs 有效,默认为 'pre' */
order?: 'pre' | 'post'
}