Open alumni opened 1 year ago
getting this as well after updating to TS 5.2.2
I have the same issue. As a temporary workaround I've set moduleResolution
to classic
in the ts-jest
configuration:
module.exports = {
transform: {
'^.+\\.tsx?$': [
'ts-jest',
{ tsconfig: { moduleResolution: "classic" } },
],
},
};
The code overrides module
in getCompiledOutput()
:
I'm running into this as well and it looks like it's been a month since the last comment. Is there a fix coming out anytime soon for this?
This patch fixed this issue for our use-case of using @tsconfig/node16
with module: node16
and moduleResolution: node16
:
--- ./node_modules/ts-jest/dist/legacy/compiler/ts-compiler.js 2023-11-01 13:05:20.000000000 -0700
+++ ./node_modules/ts-jest/dist/legacy/compiler/ts-compiler.fixed.js 2023-11-01 13:09:38.000000000 -0700
@@ -132,7 +132,7 @@
allowSyntheticDefaultImports = true;
}
else {
- moduleKind = this._ts.ModuleKind.CommonJS;
+ moduleKind = this._compilerOptions.module || this._ts.ModuleKind.CommonJS;
}
this._compilerOptions = __assign(__assign({}, this._compilerOptions), { allowSyntheticDefaultImports: allowSyntheticDefaultImports, esModuleInterop: esModuleInterop, module: moduleKind });
if (this._languageService) {
It seems like ModuleKind.CommonJS
is pretty hardwired throughout ts-jest
though so I don't know if anything is being missed here but this at least lets us run our tests with modern resolutions.
I am experiencing this as well and @erunion 's patch is fixing this issue for me.
node16
works "fine" (at least with "noEmitOnError": false
) for me even without the patch: https://github.com/kulshekhar/ts-jest/issues/4207#issuecomment-1827413759
I only encounter the issue if I do:
transform: {
'^.+\\.tsx?$': [
'ts-jest',
{
isolatedModules: true,
},
],
},
If I leave out the isolatedModules
option, it works just fine.
In addition to setting "noEmitOnError": false
, I have to leave moduleResolution
unspecified when "module": "Node16"
or "module": "NodeNext"
is set. If I set moduleResolution
to Node16
or NodeNext
, ts-jest loads the CommonJS version of some packages. See this issue here: Error TS2351 for new SchemaBuilder when testing with ts-jest
Does anyone have a workaround for when your jest config file and global setup files are in TS? It does work if my production tsconfig file sets "noEmitOnError" to false, but I don't really want to do that for production code. But with the ts-jest code seeming to invoke ts-node (from what I read) and using my default tsconfig, some of the above workarounds don't seem to work such as the transform or a custom tsconfig file.
Also, is this project dead? There hasn't been a release for over 6 months. I'm trying to figure out if we need to start looking at other projects if this project is indeed no longer being maintained.
I came here because I wanted to speed up my ts-jest
tests by applying isolatedModules: true
, which is when I started receiving this error.
I solved by it putting the following into my tsconfig.js
:
"module": "ESNext",
"moduleResolution": "Node",
I don't fully understand the practical difference between NodeNext
and ESNext
but it seems to work fine for my case (I just had to change how I import certain npm packages).
Running a trivial test went from 5 seconds to 1 ms.
Why does ts-jest change module
to CommonJS
and why this is only apparent if using isolatedModules: true
in the jest config?
If I have to guess I would say it is to change away from ESNext
if the config doesn't specify useESM
but I could be totally wrong. Also this doesn't say why only if isolatedModuels
is set.
Is it possible to fix ts-jest so it keeps the given module
option as is if it is one of CommonJS
, Node16
or NodeNext
, defaulting to CommonJS
only in other cases? Would that break something?
For people asking what the difference is between CommonJS
and NodeNext
(beware I'm not an expert) it has to do with CJS and ESM. Basically, under CommonJS
TypeScript asumes everything that uses an import
can be called with require()
; however ESM modules can't be require
ed and have to be import
ed. Under NodeNext
TypeScript tries to understand the difference between a CJS and an ESM module so it generates the right JS code. For example this code:
// source code: in a .ts file.
const x = import('./module.mjs');
generates this under CommonJS
:
// TypeScript uses `require` but wraps in a Promise. This would fail at runtime.
const x = Promise.resolve().then(() => require('./module.mjs'));
but generates this under NodeNext
:
// TypeScript uses `import` and this code is correct.
const x = import('./module.mjs');
NodeJS differentiates between the two from the extension .mjs
and TypeScript under NodeNext
makes the same distinction (plus some other things like understanding the field "type"
in package.json).
Simply not explicitly specifying moduleResolution
solved the issue for me, leaving only "module": "NodeNext"
. tsc
at least guarantees the same behavior with this config: https://www.typescriptlang.org/docs/handbook/modules/reference.html#implied-and-enforced-options
What a mess. Layer upon layer of re-interpreting configs and patching together 20 years of legacy lunacy. What a time to be alive!
In summary, ts-jest
doesn't really work with TypeScript 5.2 or above.
@erunion workround is for non ESM (without NODE_OPTIONS=--experimental-vm-modules
or useESM
is false
):
https://github.com/kulshekhar/ts-jest/issues/4198#issuecomment-1789652347
Inferring moduleResolution
is the same:
https://github.com/repobuddy/repobuddy/pull/150
When setting NODE_OPTIONS=--experimental-vm-modules
and useESM
is true
,
It will meet this condition and moduleKind
is set to ESNext
:
if ((this.configSet.babelJestTransformer || (!this.configSet.babelJestTransformer && options.supportsStaticESM)) &&
this.configSet.useESM) {
moduleKind =
!moduleKind ||
(moduleKind &&
![this._ts.ModuleKind.ES2015, this._ts.ModuleKind.ES2020, this._ts.ModuleKind.ESNext].includes(moduleKind))
? this._ts.ModuleKind.ESNext
: moduleKind;
// Make sure `esModuleInterop` and `allowSyntheticDefaultImports` true to support import CJS into ESM
esModuleInterop = true;
allowSyntheticDefaultImports = true;
}
Meaning there is no way to use moduleResolution: Node16|NodeNext
.
If you patch that and allow the moduleKind
to stay at Node16|NodeNext
, then you will get ReferenceError: exports is not defined
errors.
https://swc.rs/docs/usage/jest has been a good drop-in replacement for us.
This blocks me from doing:
moduleResolution: bundler
in main tsconfig.json
moduleResolution: nodenext
in tsconfig.test.json
isoluatedModules: true
for ts-jestConfirmed that the work in v29 resolves this for us on a module
and moduleResolution
of node16
. Thanks @ahnpnl!
This fix i breaking our packages. We have some packages in our monorepo that fail with the following setup:
package.json:
"type": "module",
tsconfig.json:
"compilerOptions": {
"outDir": "./dist",
"lib": ["ES2023"],
"module": "NodeNext",
"target": "ESNext",
"skipLibCheck": true,
"moduleResolution": "NodeNext",
"incremental": true,
"declaration": true,
}
tsconfig.test.json:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"types": ["node", "jest"],
"typeRoots": ["../../node_modules/@types"],
"moduleResolution": "Node",
"resolveJsonModule": true
},
"include": ["./src/index.spec.ts"],
"exclude": []
}
jest.config.cjs:
const config = {
preset: 'ts-jest',
testEnvironment: 'node',
extensionsToTreatAsEsm: ['.ts'],
transform: {
'^.+\\.(ts)$': [
'ts-jest',
{
useESM: true,
tsconfig: 'tsconfig.test.json',
diagnostics: {
ignoreCodes: ['TS151001'],
},
},
],
},
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
testMatch: ['**/?(*.)+(spec).[tj]s?(x)'],
testPathIgnorePatterns: ['/node_modules/', '/dist/'],
verbose: true,
reporters: ['<rootDir>/minimalReporter.cjs'],
}
module.exports = config
Can anyone please help me understand what i am doing wrong?
I am having issues importing .json files with "import * as xxx from 'x/x/x.json'" They are convertes into objects, while they are defined as arrays.
@drweizak would you please create a reproduce problem with example apps https://github.com/kulshekhar/ts-jest/tree/main/examples It would be easier to investigate. Thank you.
@drweizak would you please create a reproduce problem with example apps https://github.com/kulshekhar/ts-jest/tree/main/examples It would be easier to investigate. Thank you.
Thank you for your time! i found out the problem was related how i was importing my files. All is good now :)
before:
import * as x from 'file.json'
now:
import x from 'file.json'
@drweizak is it related to https://www.typescriptlang.org/tsconfig/#allowSyntheticDefaultImports? We did change a bit the behavior there in https://github.com/kulshekhar/ts-jest/commit/ff4b302
The issue that I'm encountering is that JSON modules, especially when imported dynamically, do not seem to be resolved the same way as tsc/node when using ts-jest. See https://github.com/kirkwaiblinger/typescript-default-json/ for some examples.
It's been hard to figure out what behavior is even correct here, since it touches on
But the ts-jest and tsc/node behavior definitely do not match.
Note that the behavior when using swc does more or less seem to match node's runtime behavior: https://github.com/kirkwaiblinger/typescript-default-json/tree/swc-variant
It's been hard to figure out what behavior is even correct here, since it touches on
- moduleResolution
- node runtime semantics
- TS's compatibility mechanisms (synthetic default imports and esmodule interop)
- resolveJsonModule (and import attributes?)
But the ts-jest and tsc/node behavior definitely do not match.
I've encountered an issue similar to the one @kirkwaiblinger is describing, but not with importing a JSON module. The issue I'm having is actually related to importing the type Delta
which is declared as the default export of the quill-delta
package.
tsc
passes, but jest
with ts-jest
fails with 'Delta' only refers to a type, but is being used as a namespace here
. This alleged TypeScript error is for using Delta.default
because Delta
's type definition uses declare class
, and setting the module
TSConfig option to 'NodeNext'
causes the imported Delta
type to be interpreted as a namespace.
Version
29.1.1
Steps to reproduce
I have a monorepo setup with multiple apps and libraries. One of the apps (the largest, the only one with
isolatedModules: true
) fails after updating to TS 5.2 with the following error:error TS5110: Option 'module' must be set to 'Node16' when option 'moduleResolution' is set to 'Node16'
.Currently using
@tsconfig/node18/tsconfig.json
for the monorepo base config, which contains the following:The
module
option is overridden byts-jest
:100
instead ofnode16
:dist/legacy/config/config-set.js
in_resolveTsConfig()
100
to1
:dist/legacy/compiler/ts-compiler.js
ingetCompiledOutput()
Expected behavior
I would expect that
module
is not changed.Actual behavior
module
is changed first to100
and later to1
(CommonJs)Debug log
extracted info above
Additional context
No response
Environment