如何查找代码库中所有属于或包含指定TypeScript类型的变量位置
TypeScript静态查找所有持有指定类型变量的实现方案
你可以通过TypeScript官方Compiler API结合类型兼容性校验实现该需求,核心是调用TypeChecker暴露的isTypeAssignableTo方法完成类型匹配,具体步骤如下:
- 第一步:加载代码库拿到目标类型实例
调用ts.createProgram加载你的整个代码库得到Program实例,再通过program.getTypeChecker()获取TypeChecker实例。遍历所有源文件的AST定位到SomeObject的类型别名声明节点,调用checker.getTypeAtLocation(类型声明节点)拿到目标类型对象targetType。 - 第二步:全量遍历AST匹配类型节点
遍历所有源文件的所有AST节点,对每个变量声明节点、标识符节点、对象属性节点等可能持有值的节点,调用checker.getTypeAtLocation(节点)获取该节点对应的推导类型currentType。 - 第三步:类型兼容性校验
调用checker.isTypeAssignableTo(currentType, targetType),返回true即说明该节点的类型和SomeObject兼容,属于你要找的持有该类型数据的节点。
如果要覆盖嵌套使用的场景,额外递归遍历对象类型的所有属性,对每个属性的类型再执行上述兼容性校验,属性类型匹配时对应父节点也需要纳入结果。
你可以参考以下最简实现代码:
import * as ts from 'typescript'; // 初始化Program加载整个代码库 const program = ts.createProgram(['src/**/*.ts'], { strict: true, // 保持和你项目一致的TS配置即可 }); const checker = program.getTypeChecker(); let targetType: ts.Type; // 定位目标类型SomeObject for (const sourceFile of program.getSourceFiles()) { if (!sourceFile.isDeclarationFile) { // 跳过d.ts声明文件可按需调整 ts.forEachChild(sourceFile, (node) => { if (ts.isTypeAliasDeclaration(node) && node.name.text === 'SomeObject') { targetType = checker.getTypeAtLocation(node); } }); } if (targetType) break; } const matchedNodes: ts.Node[] = []; // 遍历所有节点查找匹配项 for (const sourceFile of program.getSourceFiles()) { if (!sourceFile.isDeclarationFile) { ts.forEachChild(sourceFile, function traverse(node: ts.Node) { // 跳过类型声明本身 if (ts.isTypeAliasDeclaration(node) && node.name.text === 'SomeObject') return; try { const currentType = checker.getTypeAtLocation(node); // 直接匹配类型 if (checker.isTypeAssignableTo(currentType, targetType)) { matchedNodes.push(node); return; } // 检查嵌套属性 const props = currentType.getProperties(); for (const prop of props) { const propType = checker.getTypeOfSymbolAtLocation(prop, node); if (checker.isTypeAssignableTo(propType, targetType)) { matchedNodes.push(node); break; } } } catch (e) { // 忽略无法推导类型的节点 } // 递归遍历子节点 ts.forEachChild(node, traverse); }); } } // 输出所有匹配节点的位置信息 matchedNodes.forEach(node => { const sf = node.getSourceFile(); const { line, character } = ts.getLineAndCharacterOfPosition(sf, node.getStart()); console.log(`匹配位置:${sf.fileName}:${line + 1}:${character + 1}`); });
注意事项
- 你可以按需过滤节点类型,比如只保留变量声明、函数参数、类属性等节点,排除临时字面量节点即可适配不同的查找需求。
- 解构、对象展开等语法场景下TypeChecker会自动完成类型推导,不需要额外做特殊语法适配,
isTypeAssignableTo可以正确识别兼容类型。
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

