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

ts-jest运行测试报Class extends value undefined不是构造函数如何解决

问题根因

业务项目能正常运行但ts-jest跑测试报错,本质是两者的模块加载逻辑不一致:

  • ts-node默认走ESM或适配了Node.js的循环依赖处理逻辑,导出提升逻辑更宽松,循环依赖场景下能拿到正确的父类引用
  • ts-jest默认用CommonJS规范加载模块,循环依赖时加载顺序错乱,会出现父类还没完成导出就被引用,拿到undefined导致继承报错

注意:该错误是JS运行时抛出的原生类型错误,不是Jest主动拦截的错误,没有开关可以直接关闭报错,只能通过调整加载逻辑绕开。

临时兼容方案(无需大规模重构循环依赖)

下面的方案按改造成本从低到高排序:

方案1:切换ts-jest为ESM加载模式

直接对齐ts-node的加载逻辑,是改造成本最低的方案,只需要修改配置文件:

  1. 修改jest.config.js配置:
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
  preset: 'ts-jest/presets/default-esm',
  extensionsToTreatAsEsm: ['.ts'],
  testEnvironment: 'node',
  transform: {
    '^.+\\.tsx?$': ['ts-jest', {
      useESM: true,
    }],
  },
  // 如果有别名配置,需要补全后缀匹配规则
  moduleNameMapper: {
    '^(\\.{1,2}/.*)\\.js$': '$1',
  },
}
  1. 确认tsconfig.json中compilerOptions.module配置为NodeNext/ESNext,moduleResolution设置为NodeNext即可。

方案2:预加载循环依赖根模块

在jest的启动配置中提前加载所有循环依赖链的公共根模块,避免后续引用时未完成导出:

  1. 在项目根目录新建jest.setup.ts,提前引入所有报错涉及的类所属的父文件:
// 示例:提前引入基类所在文件,保证先完成导出
import './src/base/BaseClass'
import './src/common/CommonService'
  1. 在jest.config.js中添加配置:
module.exports = {
  // 其他配置不变
  setupFiles: ['<rootDir>/jest.setup.ts'],
}

方案3:局部调整循环依赖文件的导出顺序

针对单个报错的文件,微调导入导出顺序适配CommonJS的加载逻辑:

// 原代码(会报错)
import { Base } from './base'
export class Child extends Base {}

// 调整后代码
// 先占位导出
export let Child;
// 再导入依赖
import { Base } from './base'
// 实现类后赋值给导出变量
class ChildImpl extends Base {}
Child = ChildImpl;
长期优化建议

后续迭代过程中建议逐步拆分循环依赖的模块,从根本上避免不同运行环境的加载逻辑差异问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 00:54:00