TypeScript
TypeScript copied to clipboard
Module resolution: Setting `target` to `ES6` and higher results in numerous `TS2792: Cannot find module 'undici-types'` errors
Demo Repo
https://github.com/SetTrend/typescript_modres_mre
Which of the following problems are you reporting?
Something else more complicated which I'll explain in more detail
Demonstrate the defect described above with a code sample.
With following TypeScript configuration set, TSC throws numerous error TS2792: Cannot find module 'undici-types' compile time build errors.
tsconfig.json
{
"include":
[
"*.*ts"
],
"compilerOptions":
{
"target": "esnext",
"strict": true,
"noEmitOnError": true,
"noImplicitAny": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"sourceMap": true
}
}
Node.js version
> node --version
v22.15.0
npm version
> npm --version
11.4.2
Run tsc --showConfig and paste its output here
{
"compilerOptions": {
"target": "esnext",
"strict": true,
"noEmitOnError": true,
"noImplicitAny": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"sourceMap": true,
"module": "es6",
"moduleResolution": "classic",
"useDefineForClassFields": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"strictBuiltinIteratorReturn": true,
"alwaysStrict": true,
"useUnknownInCatchVariables": true
},
"files": [
"./index.ts"
],
"include": [
"*.*ts"
]
}
Run tsc --traceResolution and paste its output here
It's all in the MRE.
Paste the package.json of the importing module, if it exists
{
"name": "webpacktest",
"version": "1.0.0",
"main": "index.js",
"scripts":
{
"build": "npx tsc"
},
"author": "SetTrend",
"license": "ISC",
"description": "",
"devDependencies":
{
"ts-loader": "^9.5.2",
"typescript": "^5.8.3",
"webpack": "^5.99.9",
"webpack-cli": "^6.0.1"
}
}
Paste the package.json of the target module, if it exists
It's all in the MRE.
Any other comments can go here
It's all in the MRE.
Use moduleResolution set to node or node16 instead of classic. You shouldn't use classic.
As you may see from the description, I didn't choose classic,
Apparently, the default is wrong.
The default is documented, and not wrong per se, just undesirable in your case. I'm telling you to explicitly set it.
The documentation on moduleResolution claims:
Node10ifmoduleisCommonJS;Node16ifmoduleisNode16orNode18;NodeNextifmoduleisNodeNext;BundlerifmoduleisPreserve;Classicotherwise.
The documentation on module claims:
CommonJSiftargetisES5;ES6/ES2015otherwise.
So, target = ESNEXT ⇒ module = ES6/ES2015 ⇒ moduleResolution = Classic
If that logic doesn't work out of the box then it should be fixed.
Plus: Setting moduleResolution to node16 doesn't work. It yields loads of other errors when building.
If that logic doesn't work out of the box then it should be fixed.
The defaulting only goes one level, not multi-level like you're implying here
I don't see any defect demonstrated here. The module resolution errors are correct, and the error messages tell you what to do to fix it.
I see... Thanks for clarifying!
Nonetheless, currently compiling to ES6++ requires manually setting two additional configuration options, which is not documented. And I suppose setting them should be redundant after all. If taget = ES6 and above, then the other configuration options should fall into place, without further ado.
The defaulting only goes one level, not multi-level like you're implying here
I'd rather suggest this is less a question of levels rather than arbitrary, unspecified sequence. The question is: Is this sequence clear from the documentation? What is the sequence of setting configuration defaults? And is it made transparent to the programmer?
Rather than showing an error message to the user, suggesting the only valid value, I suggest to just apply the valid value if unset in the TSC code.
There are three ways you can determine what's going on:
- Run
--showConfig, which is always going to correctly show the computed config - Read the source code and see how it works
- Have a series of humans summarize that same source code into English prose that forms up a 30-page document, then you as a human also interpret that same document, and hope that you get to the right answer
Of these I would really advise just running --showConfig if you're unsure what the computed config is. It works 100% of the time, is much faster than even loading the tsconfig reference page, and allows for very fast iteration.
* Run `--showConfig`, which is always going to correctly show the computed config
… which is of no use when that config still won't compile.
* Read the source code and see how it works
Is this the quality standard to expect from Microsoft? Publishing crude, undocumented material and expect users to postpone their projects for digging into your source code? Is this what's to expect from "Made with ♥ in Redmond"?
This issue has been marked as "Question" and has seen no recent activity. It has been automatically closed for house-keeping purposes.