如何在Jest转换器中编程执行TypeScript命名空间导入转命名导入重构
实现方案
你可以直接调用TypeScript官方暴露的重构API完成该操作,无需依赖VS Code相关能力,具体实现步骤如下:
- 安装依赖:直接使用官方
typescript包即可,无需引入第三方工具 - 构建TypeScript语义实例
你需要先基于待处理文件和项目ts配置创建ts.Program或者ts.LanguageService实例,这是TS执行重构的基础,需要依赖完整语义分析能力。 - 定位目标导入节点
遍历解析后的AST,找到你需要转换的命名空间导入节点(即形如import * as xxx from 'xxx'的ImportDeclaration节点),记录该节点在源文件中的起止位置。 - 调用重构API获取修改
调用getRefactorsAtPosition方法传入上下文信息,筛选出id为Convert namespace import to named imports的重构项,再调用getRefactorEdits方法即可获取TS自动生成的全量修改,包含导入语句替换、后续所有命名空间调用替换为命名导入调用的所有变更。 - 应用变更输出代码
把得到的修改应用到原文件内容中,即可拿到转换后的代码。
核心示例代码
import * as ts from 'typescript'; // 初始化LanguageService,单文件处理场景更轻量 const service = ts.createLanguageService({ getScriptFileNames: () => [targetFilePath], getScriptVersion: () => '0', getScriptSnapshot: (fileName) => ts.ScriptSnapshot.fromString( fileName === targetFilePath ? sourceCode : '' ), getCurrentDirectory: () => process.cwd(), getCompilationSettings: () => yourTsConfig, getDefaultLibFileName: (options) => ts.getDefaultLibFilePath(options), }); // 定位到命名空间导入节点的位置 const sourceFile = service.getProgram()!.getSourceFile(targetFilePath)!; const namespaceImportNode = sourceFile.statements.find( s => ts.isImportDeclaration(s) && s.importClause?.namedBindings && ts.isNamespaceImport(s.importClause.namedBindings) ) as ts.ImportDeclaration; const nodePos = namespaceImportNode.getStart(sourceFile); // 获取重构项 const refactors = service.getRefactorsAtPosition(targetFilePath, nodePos); const targetRefactor = refactors?.find(r => r.name === 'Convert namespace import to named imports'); if (!targetRefactor) return; // 获取重构修改 const edits = service.getRefactorEdits( targetFilePath, nodePos, targetRefactor.name, targetRefactor.actions[0].name ); // 应用修改到原代码 let resultCode = sourceCode; if (edits?.edits.length) { // 注意按倒序应用修改,避免位置偏移 const fileEdits = edits.edits.find(e => e.fileName === targetFilePath)?.textChanges.sort((a, b) => b.span.start - a.span.start); fileEdits?.forEach(change => { resultCode = resultCode.slice(0, change.span.start) + change.newText + resultCode.slice(change.span.start + change.span.length); }); }
Jest转换器适配注意事项
如果在Jest转换器内使用,可以直接将接收的源文件内容和文件路径传入上述逻辑即可,不需要读写本地文件。如果你的项目文件量不大,直接全量构建Program即可保证语义准确性;如果对转换性能要求高,建议复用LanguageService实例,避免重复初始化的性能开销。
内容的提问来源于stack exchange,提问作者Maksym
相关产品推荐
相关产品推荐

