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

自定义TypeScript Transformer配合ts-node运行失效问题

问题原因

这个问题的核心原因是 ttypescript@1.5.13 没有适配 ts-node@10.x 的 ESM 运行模式,二者在编译钩子对接上存在兼容缺陷:

  • 开启ts-node的esm: true配置后,ts-node会先生成UnparsedSource(kind值305)类型的预解析节点做模块加载缓存
  • ttypescript在ESM模式下没有正确挂载到TypeScript的完整编译流程,直接把这个未完成语法解析的预解析节点传给了自定义转换器,没有生成标准的SourceFile节点
  • 调用getChildrenCount()这类仅SourceFile节点支持的方法时,就会触发TypeScript内部的调试断言报错,遍历节点时也只能拿到UnparsedSource类型的节点。

另外两个配置问题会放大这个兼容问题:

  • 根目录compilerOptions.plugins里给转换器加了"type": "raw"配置,这个配置仅给ttsc命令行编译使用,ts-node运行时不会识别该参数,反而会干扰ttypescript的插件加载逻辑
  • 在builder目录单独放置"type": "module"的package.json,会导致ts-node加载转换器文件时走独立的ESM模块解析逻辑,和ttypescript默认的CommonJS转换器加载逻辑冲突。
修复方案

按稳定性优先级排序:

  • 方案1(推荐,长期可用):放弃ttypescript,改用ts-patch给TypeScript打补丁的方式支持自定义转换器,完全兼容ts-node ESM模式
    操作步骤:
    1. 卸载不维护的ttypescript:npm uninstall ttypescript
    2. 安装维护状态正常的ts-patch:npm install -D ts-patch
    3. 执行补丁注入命令:npx ts-patch install
    4. 修改tsconfig.json里的ts-node配置,删除"compiler": "ttypescript"字段,ts-patch会直接修改原生typescript的编译逻辑,不需要替换编译器
    5. 删除根compilerOptions里插件配置的"type": "raw"字段,删除builder目录下单独的package.json,转换器文件和项目其他文件共用根目录的ESM配置即可
    6. 把插件配置统一放到根compilerOptions里,不需要单独给ts-node写重复的plugins配置,最终相关配置参考如下:
    {
      "compilerOptions": {
        "target": "ESNext",
        "module": "ESNext",
        "moduleResolution": "node",
        "outDir": "./build",
        "esModuleInterop": true,
        "strict": true,
        "skipLibCheck": true,
        "plugins": [
          {
            "transform": "./builder/transformer.ts",
            "after": true
          }
        ]
      },
      "ts-node": {
        "esm": true,
        "experimentalSpecifierResolution": "node"
      },
      "include": ["src"]
    }
    
  • 方案2(临时兼容,不需要换工具链):关闭ts-node的ESM模式,改用CommonJS模式运行
    操作步骤:
    1. 删除根目录package.json里的"type": "module"字段
    2. 把tsconfig里的module配置改成CommonJS,删除ts-node配置里的esm: true和experimentalSpecifierResolution字段
    3. 删除builder目录下单独的package.json,转换器按CommonJS规范编写即可
      该方案下ttypescript可以正常工作,但项目无法使用原生ESM模块特性。
  • 方案3(保留ESM的临时方案):提前把自定义转换器编译成CommonJS格式,不要让ts-node直接加载ts格式的转换器源文件
    操作步骤:
    1. 新增独立的tsconfig配置,把builder目录下的转换器提前编译成CommonJS规范的js文件
    2. tsconfig里的插件transform路径指向编译后的js文件,不要指向ts源文件
    3. 调整builder目录下package.json的配置,把编译后的转换器文件标记为CommonJS模块类型
      该方案不需要替换工具链,但每次修改转换器代码都要重新编译,调试效率低。

内容的提问来源于stack exchange,提问作者Bagel03

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 11:03:20