TypeScript: tsc should not care and fail with ts files outside of rootDir

TypeScript: 2.0.0

I have a fixtures folder which contains .ts files. In my tsconfig.json I set rootDir to src which does contain all my source code (including test).

The fixtures files are there for test cases. tsc shouldn’t complain their existence and fail the compilation.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 73
  • Comments: 90 (30 by maintainers)

Commits related to this issue

Most upvoted comments

the rootDir is used to build the output folder structure. all files have to be under rootDir for the compiler to know where to write the output. without this constraint, if there are files that are not under rootDir, the compiler has two options 1. either they will be emitted in a totally unexpected place, or 2. not emitted at all. i would say an error message is much better than a silent failure.

Bleh, this is really working as intended? I just ran into this, I told typescript that my source was all in a particular folder (via rootDir) and then it proceeded to completely ignore what I told it because I happened to have a single file with a .ts extension sitting outside of that folder.

This really feels like an error, if I tell the compiler where my source is via rootDir, it shouldn’t completely disregard that setting and change my output folder structure because it thinks maybe I did something wrong. It should just ignore any files that are not in rootDir. Alternatively, it should hard fail, not continue to emit output that doesn’t align with my desired output folder structure at all!


For anyone coming after me, the following will do what you actually want:

{
	"compilerOptions": {
		"outDir": "./output",
		"rootDir": "./source",
	},
	"include": [
		"source"
	]
}

“tsc should not care and fail with ts files outside of rootDir” I agree.

I cannot understand why typescript would be looking at JS files outside the rootDir, since that’s where all the source should be. Error message says “‘rootDir’ is expected to contain all source files”, then anything outside that directory should not be expected or assumed to be a source file, as far as TS is concerned!

If this is “Working as Intended”, then what exactly is the intent or motivation of this behavior? Is there a case where TS would want to compile source files located outside the rootDir?

On the other hand, adding an “include” section in tsconfig solves the problem. When provided with files or directories to include, TS does not go looking at other files outside that.

IMO this comment should be especially taken into account to confirm that this is indeed a bug and should be re-opened as such:

Note: A big part of the reason the current behavior of rootDir feels very wrong is precisely because it doesn’t make sense to have files outside rootDir. When one asks oneself (or the compiler) what does it mean to compile files outside rootDir the only answer is “it doesn’t make sense”.

Indeed, it does not make sense. “Source files outside rootDir” simply are not source files, no matter their file extension or content. The compiler will never compile them. So why does he complain about their existence? Is he jealous that there are files not under his rule?

+100 on this being a bug (a nasty one actually). Consider following directory structure:

- src/
  - module.ts
- test/
  - module.test.ts
- out/
  - module.js

I would like tsc to compile only the src, because I run tests with ts-node. Having rootDir: 'src' will cause compiling error currently. If you mark tests and other stuff that you only intend to execute with ts-node (or even compile separately maybe?) as “excluded”, then bad things start to happen (e.g. vscode highlighting becomes broken in tests)

In fact, no combination of rootDir, excluded and all other options satisfies all requirements (exclude tests from compilation while still being able to run them and to work with them).

And I don’t really think my use case is unique, so it’s worth reconsidering the “work as intended” label at least from UX point of view.

Had this as well. Typescript is too constraining for our team - considering flow now.

I told typescript that my source was all in a particular folder (via rootDir)

This is not what rootDir means! rootDir means “Use this folder as the relative basis for computing the paths in outDir”. Which files are part of your compilation is a separate question that is answered by files and/or include/exclude

The evil is in the naming. It really means relativePathBaseDir or something like that.

Just to add another example of the problem, this is my folder sturcture:

tsconfig.json
package.json
src/index.ts

I have in my tsconfig:

"rootDir": "src",
"outDir": "lib",

And in my “index.ts” (src folder)

import pkg from '../package.json'; // I read the package.json object

export class SomeClass {
  public version = pkg.version;
}

I know that, after the build, the “index.js” file will be inside the “lib” folder. And I know that the package.json will be 1 level up. I don’t think that Typescript should know better than me my folder structure and break the build. It should simply log a warning about some files outside the rootDir folder that weren’t included in the output folder.

@HillTravis you can trust me on this one 😃 it is our inconsistent handling of symlinks that throws the compiler off. we follow symlinks only for node module resolution, then use that name as the file name; then the we perform a check to make sure all files are under the source directory using the real path, instead of the user specified path. and that is what generates the error.

Here is my tsconfig.json:

{
    "compilerOptions": {
        "target": "es5",
        "module": "commonjs",
        "moduleResolution": "node",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "removeComments": true,
        "noImplicitAny": true,
        "rootDir": "src",
        "outDir": "build"
    },
    "exclude": [
        ".idea",
        "build",
        "node_modules",
        "typings/globals",
        "typings/modules"
    ]
}

My folder structure looks like this:

  • project
    • build
      • node_modules (symlink to …/node_modules)
    • node_modules
    • src

I want my .ts files in the src folder to be compiled and output with the same folder structures to the build folder. I do this so that I can set my document root to the build folder and keep my src out of the doc root. I’m getting error messages about .ts files in the node_modules folder, same error messages as OP. Note above, I have node_modules excluded. Why is tsc complaining about those?

I agree with @CodySchrank . I’m ok with having TS erroring out when some source file inside the rootDir references/imports a file outside of it - that is to be expected.

However, I can’t understand TypeScript to by itself look through unrelated files outside of rootDir and erroring out while those are simply configuration files for different tools, like jest or whatever. I mean, what’s the point? These are not even parts of my application and not referenced/imported anywhere directly, and my God, why would I event want them to be bundled into the resulting build in the first place…

To get around, I add “exclude” back to my tsconfig.json

@ngryman I agree that the definition of rootDir and what it’s actually doing do not seem to line up. When you create a new ts project (via tsc --init) the comment in tsconfig.json for rootDir is similar to what you quoted /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */. If I supply a directory of input files, I expect the only ones that it is even going to consider compiling are in that directory, by the definition of input.

@RyanCavanaugh It may have made sense to report an error like this 4 years ago when typescript was only used to be compiled into javascript. Of course I don’t want missing files! But now with the popularity of typescript execution, like ts-node, it seems like tsc is being a little jealous to me.

And the idea that typescript files outside of the rootDir implies an incorrect project configuration is simply wrong. I don’t need my unit tests, which are written in typescript, to be compiled to javascript. ts-node is simply faster and I get to enjoy all the benefits of typescript when writing tests.

The implication of a file outside the rootDir would be that TS would output a file outside the outDir, which I think is a self-evidently bad behavior.

The error message could be better - I’d love a suggestion or a PR for that.

The docs could always be better - again, would love concrete ideas there on how to communicate things more clearly.

Insinuating that I’m calling people stupid isn’t something I’d like any more of.

The src / test / out setup was a key scenario addressed by project references

As a test, I tried removing the symlink. Actually, I deleted the whole build folder. Then I ran tsc again, and still saw the error.

During more testing, I tried commenting out the in-code import and uses of that particular node module (ng2-datetime) and the error went away. So it’s only when I attempt to import that node module that I see the error, regardless of symlink.

If you look at the source for that package on GitHub, you’ll see that the package.json file has the “main” parameter set to “ng2-datetime.js”, although the author also published the .ts file with the same name. This seems to be causing the issue. If I create .d.ts files and delete the .ts files, the issue goes away. It compiled with no issues even after adding the symlink back.

So with all respect, I don’t see how this issue could be related to the symlink specifically. It seems to just generally cause issues when the author includes the .ts files in the package.

Do you know if there is any workaround for this? The OP above said the worked around it by adding “exclude” back to the tsconfig.json. I already have the directory excluded, but it’s still trying to compile it.

@MattiasMartens you’re implicitly conflating include and rootDir. If you have /src and /test, if include is src/* then you can’t get errors about things in /test unless something from src incorrectly imported something from test, which you should be happy about!

That’s true. I futzed about with include and found that it works better than I thought for this case, including with VSCode’s tooling.

I would still like to have code that is validated on compile but not emitted on compile, which is something that include doesn’t cover. But that is a separate request that needn’t be discussed here.

I think this is coming from a place of misunderstanding what the flags mean - they are primarily opt-in enforcement checks to help you validate that your program is configured correctly.

I’m confused by this. Do you consider rootDir an opt-in enforcement check? It affects what eventually gets emitted so it is clearly not only an enforcement check.

Some flags, like target, drastically change what will be emitted – they’re not enforcement checks but compiler instructions. rootDir reads like, and is documented like, a compiler instruction.

I strongly object to the notion that emit a non-working program should be the default.

From what I’ve read of this thread so far there seems to be a broad consensus that a reference from a file inside of rootDir to a file outside of rootDir should be an error. The aspect of the feature which I and others have found frustrating is that it does not stop there, but in fact throws an error if it finds any TS files in the project folder outside of rootDir whether a file in rootDir imports them or not.

It bears repeating: I set rootDir to the folder where my source code resides, the compiler notices other TS code in the project that has nothing to do with what’s in rootDir, and it halts! This specific behaviour does not help me understand my code. It is simply annoying.

It is true that from the perspective of the TypeScript definition of rootDir, as elaborated in this thread, the behaviour is perfectly reasonable, and everyone who has come here to express their frustration about it is in error. But it is not reasonable from the conventional, expected definition of a root directory. I put it to you that in virtually any context where I provide a root directory, I am telling the program where to begin traversing the file structure, not asking it if it’s absolutely sure there isn’t something else in the filesystem I might also be interested in.

Definitions can be wrong. They can be changed. For backwards compatibility, it is not necessary to retain definitions, only functionality.

If the feature request here is simply to treat .ts files found outside the rootDir as .d.ts

I… don’t think I want that, for pretty much the same reasons that I want the compiler to throw an error when something in rootDir imports code from outside of it. I do think the contents of a rootDir if I provide one should be encapsulated from the surrounding code.

I think the simplest way to avoid the behaviour I and others do not want is to implicitly exclude files outside of rootDir if the files in rootDir don’t refer to them. If the files in rootDir do refer to them, an error should be thrown, as it is currently.

I have also noticed that include normally means “look here as well” but in this case it means “only look here”. I would be sensible for it to have another name and be mandatory.

guys, any resolution on this now? using types from client code inside backend code and otherwise.

what’s the best option? copy-paste there and there and modify if I change types?

making one root dir for 2 projects is not an option, since why backend tsconfig.json will have info on jsx and compile into commonjs when I can use es2015

@iwllyu can you check your project on typescript@2.1.4 and file a new issue if you are still having trouble.

@mhegazy You labeled this issue with “Working as Intended” but thats not true. As you can see in my screenshot, tsc-server provides files outside of my rootDir (in this case mobiservice/src) as import suggestion. To me this looks like a bug…

not implicitly included an any input files provided to the tool

This problem is caused exactly because the user is implicitly trying to compile files outside of the rootDir. You basically told the compiler, “only compile files in this directory” and then you proceeded to reference files outside of that directory. The compiler is confused and doesn’t know how to proceed.


/project/source/index.ts

import '../external.ts'

/project/tsconfig.json

{
  "compilerOptions": {
    "rootDir": "./source"
  }
}

In this example, you tell the compiler “source files are only in the ‘source’ directory”. Then one of those files references a file that is not in the source directory. TypeScript now has two conflicting instructions, one says to only compile files in the source directory, the other says to compile files outside of the source directory.

The implication of a file outside the rootDir would be that TS would output a file outside the outDir, which I think is a self-evidently bad behavior.

I’m still very unclear about why the compiler wouldn’t just “chroot” to rootDir and don’t consider files outside of that directory. As a user, probably lacking context about tsc internals and history, this is definitely not a predictable behavior to me.

One example that I can give out of my head is Jest which offers the same option: https://jestjs.io/docs/en/configuration#rootdir-string. AFAIK Jest doesn’t consider test files outside of rootDir. I would expect the same behavior here for example.

The docs could always be better - again, would love concrete ideas there on how to communicate things more clearly.

I’m glad that you are considering improvements here. The suggestion of @MicahZoltu could be interesting to explore.

On my end, I can restate that I don’t think rootDir is predictable (hence people reaction), but as I understand it, changing the behavior of that option is not something to be considered. So as a compromise one thing I could also propose would be to rename rootDir to a more meaningful name, outBaseDir could be a candidate. But there is probably a be a better name.

Insinuating that I’m calling people stupid isn’t something I’d like any more of.

I did not insinuate anything and I’m sorry if you took it that way. I only stated a very simple fact: when users complain about something they don’t understand, there are effectively only 2 paths to take. I concluded that I hope you were not leaning to the first one. The fact that you associate yourself with one of these paths is honestly left to you.

I think I’ve said what I had to say, especially on giving candid feedback about how this thread was handled. So I’ll leave room for others to propose solutions.

@ngryman What next step do we have? rootDir has a definition - this is the common root of my source files. When a file isn’t in that common root, by the very definition of rootDir, that is an error. That definition is documented. I can’t do anything about the fact that people have invented their own definitions for rootDir and are subsequently surprised.

This is like going to Starbucks and saying that asking for a latte shouldn’t result in getting a mixture of espresso and steamed milk. It’s unactionable because you’re arguing with a definition. If you want some different drink, order something else. If Starbucks isn’t offering the kind of drink you want, make a suggestion for what that drink should be and what it should be made out of.

@mhegazy This issue was closed 3 years ago. However it seems that it’s still a source of confusion 3 years later.

Could you please revisit this “Working as Intended” status? Given the reaction of the community in this thread, it’s pretty safe to say that it is not behaving as the community expects it to behave. Whether it’s a documentation issue, renaming that option, changing its behavior, or adding a new option, I believe there is actually an action item on your side to be determined.

I can understand that you have way higher priorities than this one, but keeping this issue closed without any sign that the feedback given here has ever been valued doesn’t really convey a very good image for Typescript to be honest.

This is way too complicated. I have a monorepo and I can’t seem to find a way to properly compile each package for itself, emitting the correct directory structure, while importing local packages (from the same monorepo) using the paths option.

Either the directory structure in the output directory contains unwanted parent folders or tsc complains about files being outside the root directory.

Can’t be this complicated right?

I landed here because my assets folder contains an “MPEG Transport Stream” video file with extension .ts so it made tsc crash even if the folder wasn’t in my rootDir path 😄

I fixed it by adding the assets folder in the exclude paths but it was a disturbing behaviour 🤔

Even if I accept that, the current behavior is still in error IMO. If I have any TS files outside of the specified directory then rootDir will not be the basis for computing the paths in outDir, meaning the configuration I specified will be completely ignored.

I think hard failing would be much better because the compiler effectively thinks I have given an invalid configuration. Ignoring configuration when it is invalid is (IMO) not the right way to handle this class of failure.

Example error message that would be far more clear (along with hard failure):

TSC found typescript files outside of rootDir and therefore cannot proceed with compilation. Either change rootDir to include all typescript files, or exclude files outside rootDir, or include only files inside rootDir.

Note: A big part of the reason the current behavior of rootDir feels very wrong is precisely because it doesn’t make sense to have files outside rootDir. When one asks oneself (or the compiler) what does it mean to compile files outside rootDir the only answer is “it doesn’t make sense”. Therefore one comes to the natural conclusion that rootDir specifies sourceDir as well.

with typescript 1.8.10

I had a node_modules folder in my homedir ~/node_modules. Running tsc from my project dir ~/projects/myProject/ caused typescript to complain about the following files

../../node_modules/aws-sdk/index.d.ts(7,1): error TS1128: Declaration or statement expected.
../../node_modules/aws-sdk/index.d.ts(7,11): error TS1005: ';' expected.
../../node_modules/aws-sdk/index.d.ts(7,24): error TS1005: '{' expected.
../../node_modules/aws-sdk/lib/config.d.ts(1,1): error TS1084: Invalid 'reference' directive syntax.
../../node_modules/aws-sdk/lib/config.d.ts(29,84): error TS1110: Type expected.
../../node_modules/aws-sdk/lib/config.d.ts(36,62): error TS1110: Type expected.
../../node_modules/aws-sdk/lib/config.d.ts(68,133): error TS1110: Type expected.
../../node_modules/aws-sdk/lib/config.d.ts(75,111): error TS1110: Type expected.
../../node_modules/aws-sdk/lib/request.d.ts(1,1): error TS1084: Invalid 'reference' directive syntax.
../../node_modules/aws-sdk/lib/services/glacier.d.ts(1,1): error TS1084: Invalid 'reference' directive syntax.

very confusing - although not sure why I had a node modules folder in my home dir to begin with.

@SephReed: I’ve spent 200 rep points on StackOverflow and someone contributed this very simple solution for importing ../package.json. All you have to do is place a typings.d.ts file in the same directory as package.json, with this contents:

declare module '*.json';

I have no idea how this works, but honestly, I don’t care. At that stage, TS was forking for itself, not for me.

@sebelga I’d probably consider that a bug - allowing .json from outside rootDir would be OK since TS doesn’t copy that to the output folder

Ironically, what’s confusing is that they don’t interact: The settings do not affect each other at all. include is 100% in control of what’s in the program and rootDir is 100% in control of computing the layout of outDir.

I’ve had issues with this, as well over in https://github.com/microsoft/TypeScript/issues/31757#event-2480427393

The interplay between rootDir, include and exclude is just designed so weirdly.

I always thought that rootDir is the folder that the compiler starts traversing and include are additional folders (e.g. vendor folders) that might be referenced from rootDir.

The current definition is weird as hell and extremely unintuitive.

@RyanCavanaugh Thanks for your quick answer.

If I go to this page: https://www.typescriptlang.org/docs/handbook/compiler-options.html. I read the following definition:

Specifies the root directory of input files. Only use to control the output directory structure with --outDir.

I’m literally understanding that it’s “only used to control the output directory structure” and that’s it. The “only use” is important here. How could I even guess that it’s not the only thing that the compiler is doing in reality, but that it will also emit errors if I have Typescript files outside of that directory.

Perhaps I’m missing something, but if that’s the case, I’m far from being the only one. So if you have a product, and a good amount of your users don’t understand your product, there are only 2 paths to take: either you consider your users stupid, or either you failed to communicate something clearly. I hope you’re not leaning toward the first 😕

To finish with your Starbuck example, well write “mixture of expresso & steamed milk” in the ingredients list, so I know what a latte is, and I don’t have to guess.

@kpturner That sounds super reasonable, but — a barebones test project with no cross-folder imports will produce the behavior everyone is complaining about.

I’m guessing this is never going to be fixed. Just ran into the same issue. How this “works as intended” is beyond me. I guess the intention was to make the compiler run in a nonsensical manner.

I found this issue because I was googling why typescript was trying to compile my webpack.config.js file after I set rootDir.

I told typescript that my source was all in a particular folder (via rootDir)

This is not what rootDir means! rootDir means “Use this folder as the relative basis for computing the paths in outDir”. Which files are part of your compilation is a separate question that is answered by files and/or include/exclude

This is the answer! The docs for rootDir say

Specifies the root directory of input files

Which I took to mean “input source files”. I recommend that @RyanCavanaugh’s comment replace the current explanation for this option.

@mhegazy I’m not sure it’s the same. Yes, my structure includes a symlink, but anyplace where that symlink exists should be ignored.

In #9552, there is no src folder, meaning the node_modules folder exists in the path that is being built. In my scenario, the root directory that tsc should be looking at is src, which does not contain node_modules. So it shouldn’t be looking at that folder at all. On top of that, I have the node_modules folder explicitly excluded via my tsconfig.json. So it should be doubly ignored. I also have the build folder excluded, and that should cover the symlink to node_modules inside it.

Also, in #9552, there was no mention of the error messages or failed compilation.

I should also mention that I’m using TypeScript 1.8.10.

Specifically, the error messages read:

error TS6059: File ‘/Users/thill/Projects/nrc/client/node_modules/ng2-datetime/src/ng2-datetime/ng2-datetime.module.ts’ is not under ‘rootDir’ ‘/Users/thill/Projects/nrc/client/src’. ‘rootDir’ is expected to contain all source files.

error TS6059: File ‘/Users/thill/Projects/nrc/client/node_modules/ng2-datetime/src/ng2-datetime/ng2-datetime.ts’ is not under ‘rootDir’ ‘/Users/thill/Projects/nrc/client/src’. ‘rootDir’ is expected to contain all source files.

error TS6059: File ‘/Users/thill/Projects/nrc/client/node_modules/ng2-datetime/src/ng2-datetime/timepicker-event-interface.ts’ is not under ‘rootDir’ ‘/Users/thill/Projects/nrc/client/src’. ‘rootDir’ is expected to contain all source files.

@mhegazy Thanks for clarification. By name rootDir I took it as the root dir of source code, much like baseURL for browser. Didn’t know it is only for output folder structure.

@alexeypetrushin you can take a look at some of my projects. It seems to be working fine. e.g.:

I’m not that good at maintaining my composure when I see issues that have been open since 2016 that could probably be very fixed without introducing new issues for existing users by introducing a new “compilerOption” to let the compiler know it can ignore the error in a given use case.

For this, I apologize. I can’t help it, because I’m relied upon to provide a good service, yet I occasionally encounter issue threads like these. Why is it so difficult for the authors of TypeScript to implement one simple configuration flag?

I don’t think it’s because the developers are lazy, or because they’re unwilling to help. I don’t think anyone here is a bad person, except for myself.

It’s this conflict, this debate, which has gone on for years over what appears to be the definition of the property “rootDir”. And what to do about this issue.

People get thrown into this debate because they believe that they are right. Yes, “rootDir” serves as the base directory for the source code. Yes, the error is valid.

Yet, the underlying issue still persists. My tooling compiles the code perfectly, yet my IDE displays this error on my screen. It’s a perversion. I want those red lines gone. My files don’t have errors in them. And if they do, I should focus on those rather than being distracted by these non-issues.

All I want is to suppress this error message. I think that’s what most of us want. I don’t know if there are other cases here and maybe there are people who would like to speak up about that.

Can we please work together and solve this problem? It would make me so happy to see those red lines gone…

I told typescript that my source was all in a particular folder (via rootDir)

This is not what rootDir means! rootDir means “Use this folder as the relative basis for computing the paths in outDir”. Which files are part of your compilation is a separate question that is answered by files and/or include/exclude

@RyanCavanaugh But it is what rootDir should mean, and this is what this issue is about.

@RyanCavanaugh I can’t set it to “src” as mentioned above. I am importing “package.json” outside our src (import pkg from '../package.json';) and tsc does not allow that.

Thanks for sharing this @dylang ! I will try it.

@RyanCavanaugh I have a similar use case to @sebelga where I want to console.log out the version number from package.json at runtime.

The src / test / out setup was a key scenario addressed by project references

This requires at the least a separate project config for each root folder (https://www.typescriptlang.org/docs/handbook/project-references.html). Having read through the instructions, I came away without a good understanding of how to implement the pattern and I feel like I’m being handed a jackhammer when what I requested was a flyswatter.

Sure, maintaining adjunct modules as separate sub-projects within my source folder is more efficient, but I’m not compiling lodash here. What I want is to include many files, like test and benchmark files, under a common project folder for static analysis, and when it comes time to compile, only emit a single directory for use by the outside world. This seems easy enough to specify and I’m struggling to see why it is not only difficult for the user to do, but apparently verboten from the perspective of the TS spec.

What I want to emphasize is that the only reason this feature is disallowed is due to the compiler’s assumption of corrupt intent on the part of the developer. When the developer sets the "outDir" to ./src and the compiler finds a TS file in ./test, it could assume that this file does not need to be emitted (assuming of course that it’s not referenced from any file in “outDir”).

But it doesn’t. It assumes that the developer wanted to emit this file, and by incompetence or malice specified a subdirectory that does not contain it. In other words, the compiler has the opportunity to match the developer’s instructions to a common and reasonable use case, and instead matches it to something absurd and refuses to proceed.

As it stands, I don’t even see what the legitimate use case for "outDir" is. I’m assuming it’s to support a project structure where the tsconfig.json is at the top level along with other configuration and metadata files, and the owner wants the compiled folder to represent only the source folder that’s nested inside it. (Just make sure none of those meta-files end with .ts: that would be absurd.)

It seems to me that the design of the spec is user-antagonistic. There was a reference made to ordering a drink at Starbucks and being upset when it wasn’t what you expected, despite the ingredients being listed on the menu. This is apt as far as it goes, but I would liken this feature more to a hot dog stand that does not sell hot dogs.

Sure, the irritated customers should have gone round back and saw the big sign boldly proclaiming that the hot dog stand does not sell hot dogs. But as the confusion accumulates, there might be an opportunity for owners of the hot dog stand to reflect on how they are communicating the capabilities of their product to customers.

As I mentioned in https://github.com/microsoft/TypeScript/issues/9858#issuecomment-370653478, I think the solution to this problem is simply better error messaging. Back when I ran into it, and eventually found this GitHub issue, my biggest frustration came from how much time I wasted trying to figure out the problem, and then thinking it was a compiler bug, and then creating a repro case, and then finding a duplicate bug that says “working as intended”. Failing fast with a clear error message would have saved me all of that.

If there are source files outside of rootDir then it means the TypeScript project is configured incorrectly. Giving the user a clear message indicating this along with guidance on how to fix it I think would resolve the issue for a lot of people.

No matter which options in whatever combination I use, tsc seems not to be able to handle a monorepo with paths referencing local packages in the same monorepo. I tried --build, --project, references, paths, extends, rootDir, rootDirs, include, exclude, baseUrl, outDir in all kind of combinations with different values and in the end it complains about files not being within the rootDir or it screws up by emitting a wrong directory structure inside outDir.

Really? That I’ve never seen 😃

Excluded folders are always excluded in all my projects except where the circumstances to which I allude are present.

Are there bare bones examples on this thread? Difficult to tell from my phone.

From my own personal experience the reason a typescript build wanders off out of your rootDir tree and tries to build stuff you don’t expect is the fact the you have (deliberately or inadvertently) directly or indirectly referenced something in that area from within your rootDir. If you do that then the build will follow the reference tree regardless of whether or not you have tried to exclude the area containing the referenced file. Sometimes it can be a PITA trying to find out how/where you have done it - but invariably I find it is my own fault - not the fault of tsc. It is merely doing what I have told it to do.

Whenever this hits me it is because of types. I import an interface or something that lives in a file that imports something else that lives in a file that imports something else…until eventually I end up importing something that lives in a file outside my rootDir and very often in something I am trying to explicitly exclude in my config.

HTH some of your get to the root of your pain. No amount of config will get you out of it - you just have to keep strict control of your import structure.

I am also facing this issue and have been unable to resolve it.

tsc compilation is walking the tree out of my included directory and into parent folders, causing duplicate type errors.

I have a nested folder structure which looks like this:

project
└─src
└─package.json
└─node_modules
└─tsconfig.json
└─example
│ └─src
│ └─package.json
│ └─node_modules
│ └─tsconfig.json

Now when i try and run tsc from within the example directory, i get the following error:

node_modules/@types/react/index.d.ts:2809:14 - error TS2300: Duplicate identifier 'LibraryManagedAttributes'.

2809         type LibraryManagedAttributes<C, P> = C extends React.MemoExoticComponent<infer T> | React.LazyExoticComponent<infer T>
                  ~~~~~~~~~~~~~~~~~~~~~~~~

  ../node_modules/@types/react/index.d.ts:2814:14
    2814         type LibraryManagedAttributes<C, P> = C extends React.MemoExoticComponent<infer T> | React.LazyExoticComponent<infer T>
                      ~~~~~~~~~~~~~~~~~~~~~~~~
    'LibraryManagedAttributes' was also declared here.

As you can see by the error, tsc is walking the tree up and out of the example folder, and looking in the node_modules folder of the parent directory! What feels even worse is that i have tried explicitely ignoring the parent node_modules directory with little effect.

Here is the tsconfig of the example diretory:

{
  "compilerOptions": {
    "target": "es5",
    "experimentalDecorators": true,
    "module": "commonjs",
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "moduleResolution": "node",
    "lib": ["es2017", "dom"],
    "jsx": "react"
  }
,
  "typeRoots": [
    "./node_modules/@types"
  ],
  "include": [
    "src"
  ],
  "exclude": [
    "node_modules",
    "../node_modules"
  ]
}

How can i solve this issue? None of the above seems to work out for me