如何使用ts-morph移除未使用的对象字面量属性?
检测并移除lang对象中未使用的属性
你可以借助ts-morph的引用查找API实现这个需求,核心思路是遍历lang对象的每个属性,查找整个项目中对该属性的所有引用,确认无引用后移除属性。以下是具体实现方案:
核心实现代码
const project = new Project({ tsConfigFilePath: 'tsconfig.webpack.json' }); const source = project.addSourceFileAtPathIfExists('constants.ts'); if (!source) return; const messages = source.getVariableDeclarationOrThrow('lang'); const value = messages.getInitializerOrThrow() as ObjectLiteralExpression; // 检查属性是否被使用的工具函数 function checkPropertyUsage(rootNode: VariableDeclaration, propPath: string): boolean { const references = rootNode.findReferences(); for (const ref of references) { for (const refNode of ref.getReferences()) { const node = refNode.getNode(); let currentPath = ''; let currentParent = node.parent; // 追踪属性访问链,比如 lang.nested.value 会解析成 "nested.value" while (currentParent instanceof PropertyAccessExpression) { currentPath = currentParent.getName() + (currentPath ? `.${currentPath}` : ''); currentParent = currentParent.parent; } // 检查解构赋值中的属性 if (currentParent instanceof ObjectLiteralExpression) { const prop = currentParent.getProperty(propPath.split('.')[0]); if (prop) { // 处理嵌套解构,比如 const { nested: { value } } = lang if (propPath.includes('.')) { const nestedPropPath = propPath.split('.').slice(1).join('.'); return checkPropertyUsage(rootNode, nestedPropPath); } return true; } } // 检查直接属性访问或函数调用 if (currentPath === propPath) { // 处理函数调用场景,比如 lang.calculate() if (currentParent instanceof CallExpression && currentParent.getCallee() === node.parent) { return true; } return true; } } } // 动态属性访问(如 lang[var])无法静态检测,默认视为已使用(可按需调整) return false; } // 递归遍历所有属性(含嵌套) function traverseProperties(objExpr: ObjectLiteralExpression, parentPath = '') { const properties = objExpr.getProperties(); for (const prop of properties) { if (!(prop instanceof PropertyAssignment)) continue; const propName = prop.getName(); const fullPath = parentPath ? `${parentPath}.${propName}` : propName; const initializer = prop.getInitializer(); // 先处理嵌套对象的子属性 if (initializer instanceof ObjectLiteralExpression) { traverseProperties(initializer, fullPath); // 若子属性全被移除,且嵌套对象本身未被直接访问,则移除该嵌套对象 const isNestedUsed = checkPropertyUsage(messages, fullPath); if (!isNestedUsed && initializer.getProperties().length === 0) { prop.remove(); } } else { // 检查当前属性是否被使用,未使用则移除 const isUsed = checkPropertyUsage(messages, fullPath); if (!isUsed) { prop.remove(); } } } } // 启动遍历处理 traverseProperties(value); // 保存修改后的文件 source.save();
关键说明
- 覆盖三种常见使用场景:直接属性访问(
lang.hello)、解构赋值(const { hello } = lang/const { nested: { value } } = lang)、函数调用(lang.calculate(10))。 - 动态属性访问(如
lang[dynamicKey])无法通过静态分析检测,代码中默认标记为已使用,可根据项目需求调整这部分逻辑。 - 嵌套属性处理会先清理子属性,若嵌套对象本身无直接引用且已无子属性,会一并移除。
内容的提问来源于stack exchange,提问作者JPS
相关产品推荐
相关产品推荐

