You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 09:24:02