如何在使用TypeScript编写的ESM模块中处理Jest的相对导入问题?
I’ve run into this exact conflict before—your setup makes total sense for ESM output, but ts-jest’s real-time transpilation doesn’t natively map those .js extensions in your TS imports back to the actual .ts files. Here’s how to fix it step by step:
Solution Steps
1. Add Module Path Mapping (Critical Fix)
Add a moduleNameMapper to your jest.config.js to redirect requests for .js files to their corresponding .ts sources. This tells Jest to look for the original TypeScript files instead of the non-existent compiled JS files during testing:
moduleNameMapper: { // Match relative paths ending with .js, and map them to .ts files '^(\\.{1,2}/.*)\\.js$': '$1.ts', }
If you work with .tsx files too, adjust the regex to match both:
moduleNameMapper: { '^(\\.{1,2}/.*)\\.js$': '$1.tsx?$', }
2. Configure Jest to Recognize ESM Extensions
Add extensionsToTreatAsEsm to ensure Jest treats your TypeScript files as ESM modules, aligning with your compile target and avoiding parsing errors:
extensionsToTreatAsEsm: ['.ts', '.tsx'],
3. Align tsconfig.json with Node.js ESM Rules
Update your tsconfig.json to use a module resolution strategy that matches Node.js ESM behavior, so TypeScript’s compilation and Jest’s transpilation stay consistent:
{ "compilerOptions": { "module": "ES2020", "moduleResolution": "NodeNext", // Or Node16, matches your ES module setup "target": "ES2020", "esModuleInterop": true, "skipLibCheck": true, "strict": true } }
Full Updated jest.config.js
Putting it all together, your config should look like this:
/** @type {import('jest').Config} */ const config = { collectCoverage: true, preset: 'ts-jest/presets/default-esm-legacy', setupFiles: ['./src/jest-setup.ts'], testEnvironment: 'node', testMatch: ['**/__tests__/**/*.[t]s?(x)', '**/?(*.)+(spec|test).[t]s?(x)'], extensionsToTreatAsEsm: ['.ts', '.tsx'], moduleNameMapper: { '^(\\.{1,2}/.*)\\.js$': '$1.ts', }, transform: { '^.+\\.tsx?$': [ 'ts-jest', { useESM: true }, ], } }; export default config;
Why This Works
Your choice to add .js extensions in TS imports is correct for Node.js ESM compliance—TypeScript won’t auto-add these extensions during compilation, so manual inclusion is necessary. The problem is that ts-jest tries to resolve the exact path you wrote, but the .js files don’t exist in your src directory yet.
The moduleNameMapper redirects those .js path requests to the actual .ts files, while extensionsToTreatAsEsm ensures Jest handles those files as ESM modules, matching your production build setup.
内容的提问来源于stack exchange,提问作者Harshal Patil

