TypeScript
TypeScript copied to clipboard
tsc not respecting types/typeRoots config for imported modules
Bug Report
Codebase is pulling in type declarations from the parent ../node_modules/@types/ folder, despite attempting to restrict the types and typeRoots to ignore it.
client/
node_modules/@types/foo/ # server shouldn't ever see this!
tsconfig.json
server/
node_modules/foo/ # server should see this as a module with no type declarations
tsconfig.json
🔎 Search Terms
- Stop typescript from including types from parent node_modules
- Prevent typeRoots from using parent node_modules
Related Issues:
- How to block typescript 2.0 from walking up all parent directories while resolving modules? #13992
- Declarations are unexpectedly used from node_modules in parent directory #30124
The issue is very similar to the ones described above, but neither were resolved beyond saying that unwanted types could be excluded with "types": []. This only seems to work for excluding global types (e.g. @types/node) as far as I can tell, there is no way to prevent typescript pulling in types for a module that is explicitly imported. See repro for more context.
🕗 Version & Regression Information
We are seeing this problem with [email protected], but I have created a reproduction that also confirms it on typescript@latest and typescript@next too.
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about excluding types and type roots.
💻 Code
Reproduced in repo with CI demonstrating incorrect behaviour here: https://github.com/danprince/typeroots-bug-repro
🙁 Actual behavior
The server codebase ends up including ../node_modules/@types/foo/index.d.ts as part of the compilation (through an import foo from "foo") even with "typeRoots": ["./node_modules/@types"] and "types": [].
Our current workaround is to remove the parent node_modules as part of our CI step.
We could also work around this by shadowing the declarations in the local node_modules/@types dir, or using paths hack to point typescript towards a non-existent version of the module, but it shouldn't be that hard.
All I want is to tell tsc is to never ever look in ../node_modules/@types.
🙂 Expected behavior
Never look in ../node_modules/@types for anything. I know that conflicts with the "moduleResolution": "node" to some degree, but it should be possible to configure that as far as type declarations are concerned.
This is the intended behavior of module resolution. If other people encounter this with some frequency we could think about some new option to change module resolution, but it'd be a new switch of some kind.
Understood. Thanks!
Our use case here is probably too specific to ever be worth changing the module resolution behaviour, but I could definitely see it being worth an additional note in the docs.
I had been thinking that the general concept of the node_modules/@types directory was fully configurable with typeRoots, rather than being a distinct part of module resolution.
Is there a workaround? Or is the solution never to nest projects?
I am also looking for a solution here. I have two nested projects, and the nested one tries to look in ../node_modules/@types instead of resolving from its own node_modules/@types folder.
Bumping this, we've also encountered this issue. it had the effect of a parent module in ../node_modules/@types causing tsc --noEmit for child projects to pass in CI (not only was the missing package error not shown, the actual compilation errors did not appear either). This caused code to be deployed our servers, to which it promptly died upon compilation.
Forgive my nativity around how TS handles module resolution; If we can't change the behavior, would it be possible to have a warning of some kind that typeRoots is being ignored and that type modules are still being consumed from the parent by the child project? Or maybe just a documentation update around typeRoots? The way it's written right now implies this shouldn't be possible.
Outside of the silent failure from tsc --noEmit which may be another issue, this would have at least pointed us towards a solution a lot quicker.
We also went for removing the parent ../node_modules/@types before running tsc --noEmit as our work-around.
It appears to me (I don't have a convenient isolated test case) that the problem from multiple past issues still exists also: TypeScript looks up to ../node_modules/@types/ for global types, no matter what combination of typeRoots, types, etc. is configured. It's a significant problem with manually or automatically hoisted dependencies in a monorepo.
Isn't this behavior directly contradicts typeRoots documentation ,which states If typeRoots is specified, only packages under typeRoots will be included ?? If this documentation is incorrect and behavior is expected, maybe at least documentation should be changed, stating that 'only packages under typeRoots will be included and also everything that falls under ../node_modules/@types, etc , etc'?
Just tried configuring both
"types": [] and "typeRoots": [] - got ../node_modules/@types included still. Quite counterintuitive and definitely misleading in documentation
I’ve been hit by this problem as well. In my case I just wanted to turn of resolution of node_modules/@types completely, which should be possible according to the documentation. So i’ve set typeRoots to an empty array, but this doesn’t have any effect.
This is a real pain for monorepo DX — it's impossible to get realtime feedback in IDE or in a development environment due to this issue.
I've had to resort to rm -rf ../node_modules on CI, but that's not realistic on a dev machine during every day dev work.