ts-jest 的 useESM 配置:让 Jest 以 ESM 语法运行 TypeScript 测试
发布时间:2026/10/7 2:21:45 锦皓数字建站

测试开发工具【免费下载链接】ts-jestA Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.项目地址https://gitcode.com/gh_mirrors/ts/ts-jest点击查看免费下载useESM是ts-jest提供给 Jest transformer 的核心开关它决定ts-jest在编译 TypeScript 时尽可能输出 ESMECMAScript Modules语法还是输出传统 CommonJS 语法。本文将以useESM选项为主线讲解它的默认行为、在jest.config.ts中的完整配置方式、与 Jest ESM 运行时及tsconfig模块策略的配合方法并结合 ts-jest 仓库源码说明该选项在底层是如何生效的。读完本文你将能够把基于 TypeScript 的 Jest 测试工程完整切换到 ESM 模式并处理.mts/.mjs扩展名等进阶问题。useESM 选项是什么useESM是ts-jesttransformer 的一个布尔配置项官方文档website/versioned_docs/version-29.4/getting-started/options/useESM.md对其的定义非常明确TheuseESMoption allowsts-jestto transform codes to ESM syntaxif possible.即该选项让ts-jest在条件允许的情况下将代码转换为 ESM 语法。这里的关键词是 if possible它意味着useESM并不是一个无条件强制输出 ESM的开关而是需要与 Jest 的 ESM 运行时能力配合才能生效下文底层原理一节会详细说明。在 src/types.ts 中可以看到该选项的类型定义与注释/** * Tell ts-jest to transform codes to ESM format. This only works in combination with jest-runtime ESM option * supportsStaticESM true which is passed into Jest transformer */ useESM?: boolean类型注释再次强调该选项只有在 Jest 运行时通过supportsStaticESM: true告知 transformer 支持静态 ESM 时才真正起作用。默认值false输出 CommonJS文档明确说明useESM的默认值是false此时ts-jest会把代码转换为CommonJS语法。这在 src/legacy/config/config-set.ts 的配置类字段声明和 src/legacy/config/config-set.ts 的解析逻辑中都有印证// 字段默认值 useESM false // 配置解析未显式提供时回退为 false this.useESM options.useESM ?? false因此如果项目没有任何 ESM 相关配置ts-jest默认行为就是把 TS 编译成 CommonJS 模块这也是绝大多数传统 Jest 工程的默认形态。完整配置示例在jest.config.ts中开启useESM的最小配置如下取自官方文档原始示例import type { Config } from jest const jestConfig: Config { // [...] transform: { // ^.\\.[tj]sx?$ to process ts,js,tsx,jsx with ts-jest // ^.\\.m?[tj]sx?$ to process ts,js,tsx,jsx,mts,mjs,mtsx,mjsx with ts-jest ^.\\.tsx?$: [ ts-jest, { useESM: true, }, ], }, } export default jestConfig注意示例中两行注释的含义^.\\.[tj]sx?$匹配.ts、.js、.tsx、.jsx不包含.mts/.mjs等带m前缀的扩展名^.\\.m?[tj]sx?$在上一模式基础上额外匹配.mts、.mjs、.mtsx、.mjsx这是 ESM 场景下更推荐使用的 transform 模式。这两个正则模式在 src/constants.ts 中都有对应的具名常量例如ESM_TS_TRANSFORM_PATTERN ^.\\.m?tsx?$建议在实际工程中直接导入这些常量以避免手写正则出错。if possible 的底层原理supportsStaticESMuseESM: true只是尽力而为真正决定输出 ESM 还是 CommonJS 的是useESM与 Jest 传入的supportsStaticESM标志的组合判断。在 src/legacy/compiler/ts-compiler.ts 中可以看到核心逻辑getCompiledOutput(fileContent: string, fileName: string, options: TsJestCompileOptions): CompiledOutput { const isEsmMode this.configSet.useESM options.supportsStaticESM this._compilerOptions this.fixupCompilerOptionsForModuleKind(this._initialCompilerOptions, isEsmMode) // ... }也就是说只有当useESM为 true且Jest 运行时声明支持静态 ESMsupportsStaticESM: true时ts-jest才会进入 ESM 编译模式否则即使配置了useESM: true最终也会回退为 CommonJS 输出。在 legacy 转换器 src/legacy/ts-jest-transformer.ts 中这一判断还会进一步影响传给 TypeScript 的module取值以及.mjs文件名的保留策略compilerOptions: { ...configs.parsedTsConfig.options, module: transformOptions.supportsStaticESM transformOptions.transformerConfig?.useESM ? ts.ModuleKind.ESNext : ts.ModuleKind.CommonJS, }, // .mjs fileName causes ts.transpileModule to preserve ESM syntax even with module: CommonJS fileName: transformOptions.supportsStaticESM transformOptions.transformerConfig?.useESM ? sourcePath : sourcePath.replace(/\.mjs$/, .js),从源码可以推断当 ESM 模式激活时ts-jest会把module强制为ESNext并保留.mjs文件名以保证transpileModule输出原生 ESM 语法。如何让 supportsStaticESM 为 truesupportsStaticESM是 Jest 运行时通过--experimental-vm-modules标志启用 ESM 支持后在 transformer 调用链中自动传入的。也就是说只改jest.config.ts是不够的还必须以 ESM 模式启动 Jest详见下文启动 Jest ESM 运行时一节。这一点也是文档中See more about ESM support in dedicated guide提示指向 website/docs/guides/esm-support.md所强调的前提。配套 tsconfig 配置开启useESM: true后还需要保证tsconfig的module配置与 ESM 目标一致。esm-support 指南给出了两类可选方案二选一方案一使用 ES 系列 module 值{ compilerOptions: { module: ES2022, // or ESNext target: ESNext, esModuleInterop: true } }可选值包括ES2015、ES2020、ES2022、ESNext等。指南特别建议优先使用ES2022或ESNext以完整支持近年 ESM 新特性如顶层 await、import 属性等。方案二使用 hybrid 模块值Node16/Node18/NodeNext{ compilerOptions: { module: Node16, // or Node18/NodeNext target: ESNext, esModuleInterop: true, isolatedModules: true } }使用 hybrid 值时有两条硬性约束package.json中必须包含type: module二者必须配套当前代码转译器仅支持hybrid 值配合isolatedModules: true使用这是 ts-jest 在 website/docs/guides/esm-support.md 中明确标注的限制。启动 Jest ESM 运行时由于 Jest 原生以 CommonJS 方式运行要真正让useESM生效必须用 Node 的实验性 VM 模块标志启动 Jestnode --experimental-vm-modules node_modules/jest/bin/jest.jsYarn 用户可以使用等价的替代命令同样兼容 Yarn PlugnPlayyarn node --experimental-vm-modules $(yarn bin jest)如果 Jest 配置文件本身用 TypeScript 编写还需要安装ts-node作为开发依赖npm install -D ts-node从源码测试用例如 src/legacy/ts-jest-transformer.spec.ts可以看出测试中正是通过传入supportsStaticESM: true与transformerConfig: { useESM: true }的组合来驱动 ESM 编译路径的这与运行时行为一致。使用 ESM presets 简化配置除了手动在transform中写useESM: true更推荐使用 ts-jest 提供的 ESM preset 工厂函数。完整 preset 列表见 website/versioned_docs/version-29.4/getting-started/presets.md。import type { Config } from jest import { createDefaultEsmPreset } from ts-jest const presetConfig createDefaultEsmPreset({ //...options }) export default { ...presetConfig, } satisfies Config在 src/presets/create-jest-preset.ts 中可以确认ESM preset 内部会自动设置useESM: true并在返回配置中附带extensionsToTreatAsEsmsrc/constants.ts 中定义为[.ts, .tsx, .mts]。对应的预设类型定义见 src/types.ts其 transform 模式为export type DefaultEsmPreset { extensionsToTreatAsEsm: string[] transform: { [ESM_TS_TRANSFORM_PATTERN]: [ts-jest, { useESM: true } DefaultEsmTransformOptions] } }如果不使用 preset则需手动补齐extensionsToTreatAsEsm与 ESM transform 模式import type { Config } from jest import { TS_EXT_TO_TREAT_AS_ESM, ESM_TS_TRANSFORM_PATTERN } from ts-jest export default { extensionsToTreatAsEsm: [...TS_EXT_TO_TREAT_AS_ESM], transform: { [ESM_TS_TRANSFORM_PATTERN]: [ ts-jest, { //...other ts-jest options useESM: true, }, ], }, } satisfies Config仓库的 E2E 测试给出了一个真实的落盘示例e2e/esm-features/jest-compiler-esm.config.ts 中同时设置了extensionsToTreatAsEsm: [.ts]与useESM: true并配合module: ESNext的 tsconfige2e/esm-features/tsconfig-esm-transpiler.spec.json。解析 .mjs / .mts 扩展名要使用.mts扩展名除了满足 ESM 模式运行前提外还有两条额外要求package.json需包含type: module需要自定义 Jest resolver把.mjs请求解析到对应的.mts文件例如import type { SyncResolver } from jest-resolve const mjsResolver: SyncResolver (path, options) { const mjsExtRegex /\.mjs$/i const resolver options.defaultResolver if (mjsExtRegex.test(path)) { try { return resolver(path.replace(mjsExtRegex, .mts), options) } catch { // use default resolver } } return resolver(path, options) } export default mjsResolver然后在 Jest 配置中挂载import type { Config } from jest const config: Config { //...other options resolver: rootDir/path/to/custom-resolver.ts, }另外从 src/legacy/ts-jest-transformer.ts 的源码可以看到.mjs文件名在 ESM 模式下会被原样保留传给transpileModule这是保证输出仍为 ESM 语法的关键细节。pathsToModuleNameMapper 的 useESM 选项useESM还以参数形式出现在 ts-jest 的路径映射工具pathsToModuleNameMapper中src/config/paths-to-module-name-mapper.tsexport const pathsToModuleNameMapper ( mapping: TsPathMapping, { prefix , useESM false }: { prefix?: string; useESM?: boolean } {}, ): JestPathMapping {当useESM: true时该工具会额外生成两类映射规则见 src/config/paths-to-module-name-mapper.ts 与 src/config/paths-to-module-name-mapper.ts为每个路径别名追加.js后缀匹配模式如^alias/(.*)\.js$以兼容 ESM 下必须带扩展名的导入写法追加^(\\.{1,2}/.*)\\.js$ → $1规则将相对路径导入中的.js后缀剥离回真实源文件。对应测试见 src/config/paths-to-module-name-mapper.spec.ts其中明确验证了useESM: true时会为 resolved config 追加js扩展名的映射。E2E 验证ESM 特性实测仓库在e2e/esm-features目录下提供了针对 ESM 能力的端到端测试测试用例 e2e/esm-features/tests/esm-features.spec.ts 覆盖了典型 ESM 特性import.meta元属性访问JSON 模块的 import 断言with { type: json }动态导入与 import 属性顶层 awaittop-level await。这些用例只有在useESM: true且 Jest 以 ESM 模式运行时才能通过是验证整条 ESM 链路是否配置正确的直接手段。小结与注意事项useESM默认值为false输出 CommonJS设为true后ts-jest会在条件允许时输出 ESM 语法。条件允许意味着必须同时满足Jest 以--experimental-vm-modules启动从而传入supportsStaticESM: true以及tsconfig的module配置为 ES 系列值或 hybrid 值后者需配合type: module与isolatedModules: true。使用createDefaultEsmPreset等 preset 工厂函数可自动生成useESM: trueextensionsToTreatAsEsm ESM transform 模式的组合配置推荐优先采用。若涉及.mts/.mjs还需type: module与自定义 resolver 配合路径别名场景下可结合pathsToModuleNameMapper的useESM: true参数生成兼容 ESM 的映射。更多完整的 ESM 配置示例可参考仓库 examples 目录下的jest-esm.config.ts、tsconfig-esm.json等文件以及官方 ESM 指南 website/docs/guides/esm-support.md。赞分享测试开发工具【免费下载链接】ts-jestA Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.项目地址https://gitcode.com/gh_mirrors/ts/ts-jest点击查看免费下载相关推荐livox_ros_driver2自动连接模式工作原理LidarInfoChangeCallback回调实战livox_ros_driver2自动连接模式工作原理LidarInfoChangeCallback回调实战 一、什么是自动连接模式 livox_ros_dr测试开发工具NumPy NEP 提案体系与开发路线图完全指南从 NEP 0 流程到 doc/neps 目录结构解析NumPy NEP 提案体系与开发路线图完全指南从 NEP 0 流程到 doc/neps 目录结构解析 本文是 NumPy 增强提案NEPNumPy En测试开发工具ts-jest 的 ESM 支持完整指南Jest 运行时、tsconfig 与 Jest 配置三步走ts jest 的 ESM 支持完整指南Jest 运行时、tsconfig 与 Jest 配置三步走 本篇技术指南以 ts jest 在 Jest 中运行 E测试开发工具上一篇如何用DownKyi哔哩下载姬高效管理B站视频终极免费解决方案下一篇DownKyi哔哩下载姬免费高效的B站视频下载终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。