TypeScript中如何按类型处理解析树中的不同节点?
在TypeScript中安全处理递归AST节点类型的方案
一、修复类型定义,启用自动类型窄化
你的核心问题之一是原始类型定义中X的type是宽泛的string类型,TypeScript无法通过x.type === 'a'这类判断自动推断具体类型。需要将类型标识改为字符串字面量类型,让TS能基于type属性做精确的类型窄化:
// 用泛型基类统一类型标识 type X<T extends string> = { type: T } type A = X<'a'> & { list: Array<A | B | C> } type B = X<'b'> & { value: A | B | number } type C = X<'c'> & { value: string } // 节点实例保持不变 const a1: A = { type: 'a', list: [] } const a2: A = { type: 'a', list: [] } const a3: A = { type: 'a', list: [] } const b1: B = { type: 'b', value: a1 } const b2: B = { type: 'b', value: b1 } const b3: B = { type: 'b', value: 200 } const c1: C = { type: 'c', value: 'foo' } const c2: C = { type: 'c', value: 'bar' } const c3: C = { type: 'c', value: 'baz' } a1.list.push(b1, a2, b2, b3) a2.list.push(a1, a3, b3, c1) a3.list.push(b2, c2, c3) const x: A = { type: 'a', list: [a1, a2, a3] }
二、实现类型安全的递归遍历函数
修正handle函数的参数类型(覆盖所有节点类型),此时TS会基于type自动推断节点类型,无需手动断言:
function handle(node: A | B | C): void { if (node.type === 'a') { // TS自动推断node为A类型,list属性类型明确 node.list.forEach(handle) } else if (node.type === 'b') { // TS自动推断node为B类型 if (typeof node.value === 'number') { console.log(node.value) } else { // 剩余类型自动推断为A|B,可安全递归调用handle handle(node.value) } } else if (node.type === 'c') { // TS自动推断node为C类型 console.log(node.value) } } handle(x)
三、处理解析器中动态类型节点(如栈顶元素)
对于const node = stack[stack.length - 1]这类动态类型场景,避免直接用as SomeType做类型断言,而是用类型守卫函数结合运行时检查,兼顾类型安全和灵活性:
// 定义类型守卫函数,同时做运行时验证和类型推断 function isA(node: A | B | C): node is A { return node.type === 'a' } function isB(node: A | B | C): node is B { return node.type === 'b' } function isC(node: A | B | C): node is C { return node.type === 'c' } // 使用示例 const stack: Array<A | B | C> = [a1, b2, c3] const node = stack[stack.length - 1] if (isA(node)) { // node类型自动推断为A,可安全访问list属性 node.list.push(c1) } else if (isB(node)) { // node类型自动推断为B,可安全访问value属性 if (typeof node.value === 'number') { console.log(node.value) } } else if (isC(node)) { // node类型自动推断为C console.log(node.value) }
核心要点总结
- 用字符串字面量替代宽泛的
string作为类型标识,触发TypeScript的自动类型窄化 - 函数参数需覆盖所有可能的节点类型,避免类型遗漏
- 类型守卫函数是替代类型断言的更安全方案,通过运行时检查验证类型合法性
- 递归处理节点时,TS会基于类型守卫自动推断后续操作的类型,无需手动干预
内容的提问来源于stack exchange,提问作者Lance Pollard
相关产品推荐
相关产品推荐

