- 定义树状结构对象类型:
- 假设树状结构节点有
id
(唯一标识)、name
(节点名称)和 children
(子节点数组)属性。可以这样定义类型:
interface TreeNode {
id: number;
name: string;
children: TreeNode[];
}
- 这样就定义了一个递归类型,
TreeNode
类型的 children
数组元素又是 TreeNode
类型。
- 添加新节点与访问节点属性的类型提示:
function addChild(parent: TreeNode, newChild: TreeNode) {
parent.children.push(newChild);
return parent;
}
// 调用函数时会有正确的类型提示
let root: TreeNode = { id: 1, name: 'Root', children: [] };
let newNode: TreeNode = { id: 2, name: 'Child', children: [] };
addChild(root, newNode);
function printNodeName(node: TreeNode) {
console.log(node.name);
}
printNodeName(root);
// 这里访问 `node.name` 时会有正确的类型提示,因为 `node` 被推断为 `TreeNode` 类型
- 类型推断在处理递归类型定义时的要点:
- 递归边界:递归类型定义必须有明确的边界,否则会导致类型检查无限循环。例如在上述
TreeNode
类型中,虽然 children
是 TreeNode[]
,但数组最终会有尽头,不存在无限制的嵌套。
- 使用接口:使用接口(
interface
)来定义递归类型是一种常见且清晰的方式。接口可以重复声明扩展,方便在不同地方对递归类型进行补充定义。
- 类型别名:也可以使用类型别名(
type
)来定义递归类型,例如 type TreeNode = { id: number; name: string; children: TreeNode[] };
,但在某些复杂场景下,接口的扩展性可能更有优势。
- 类型检查工具:依赖 TypeScript 的类型检查机制,在编译时确保递归类型的使用符合定义,防止错误的类型赋值和操作。