Open donaldpipowitch opened 4 years ago
Maybe they shouldn't be mixing test and source files?
The extends
, files
, include
and exclude
options can be used in most cases,
https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#configuration-inheritance-with-extends
https://github.com/Microsoft/TypeScript/issues/8435#issuecomment-216692451
https://github.com/microsoft/TypeScript/issues/8435#issuecomment-216694219
Maybe they shouldn't be mixing test and source files?
That's what I suggest as well, but I'm not the majority as far as I can tell. The community seems to prefer it differently.
I understand the old comment from @mhegazy that a tsconfig.json matches one tsc call. Maybe we need a tsconfig-compose.json or something similar in that case. Something which editors can automatically pick up to get the correct project configuration. Even Microsofts React Starter mixed source and test files and now recommends CRA which does the same. (It's also not just tests and sources. It can be some configuration files, storybook stories and so on mixed in the same directory.)
mixing test and source files
It's called "colocating" and it's a common pattern in the JavaScript world.
Exhibit A:
In a component-based architecture, we already combine templates, stylesheets, and JavaScript in one directory. As it makes sense to group these tightly-coupled files together, including unit tests in this selection is the natural extension of the underlying model.
https://islovely.co/posts/colocating-unit-tests
Exhibit B:
It’s so much nicer to colocate tests with sources (either separate folder or *.test.js files). Can’t see any reasons to do it any other way.
https://twitter.com/dan_abramov/status/762658867327172608?lang=en
FYI: I haven't tried it, but it could be that this problem can now be solved by having “Solution Style” tsconfig.json Files.
Something like this:
// tsconfig.json
{
"files": [],
"references": [
{ "path": "./tsconfig.src.json" },
{ "path": "./tsconfig.test.json" },
]
}
If that works it would probably make this issue obsolete.
I've tried the "solution project" approach without success: https://gist.github.com/aleclarson/6ae9a3b6b9d06c492fb9a3b6ec395411
This would be super useful. Without this, we need separate tsconfig for source and test files, separate build, dev scripts etc etc. Meanwhile, our eslint config can stay in a single file and can use unified scripts because of the overrides capability allowed there.
Does anyone know when a solution for the problem specified by the author will be available? Like some people here mentioned, it is a common pattern to put source and test files together. Another example where defining tsconfig for specific files only would be useful is Jest + Cypress. Both of these provide global definitions for methods like expect or describe. Now with the recent addition of Cypress Components I can imagine people using Jest for unit testing methods whilst Cypress Components, as the name suggests, for components in frameworks like Vue or React.
I would also support the addition of this feature. Am currently migrating a codebase to typescript and it would be nice to specify strict compiler options on .ts
files whilst having weaker rules on the .js
ones. This way the check javascript flag can be enabled immediately without having to chose between being overwhelmed by errors in the javascript files or weaker compiler settings in the newly made typescript files.
As a concrete example it could be nice to allow typescript files to be written with strict mode true, yet have the javascript files include the strictFunctionTypes
compiler setting so that we can check that any newly typed functions imported to the javascript files are being used correctly immediately. If there is already a way to do this then I would appreciate any advice as I can't seem to find an explanation or working implementation for how to do this.
One pretty common use case I think would be in mono-repository architectures, where you have multiple packages all having their own src
, test
, etc. directories. You want to be able to enforce a specific config for ALL test
files, ALL src
files, etc. For example, you might want to enable isolatedModules
for src
files since they're compiled using Babel, but not for test
files, in which it's not needed. In this scenario, the overrides syntax offered by ESLint (which would have suffered from the same limitation otherwise) comes in very handy indeed.
Colocating test, source and other types of files has been widely adopted as a pattern because it just makes sense for discoverability to group files by their concern and not their type. Test files in particular could benefit from looser types, which is why I've long wished that TypeScript would support overrides for colocated files and not just different directories. Lacking support for it means, for example, that people sometimes work around it with ts-nocheck
directives, losing even the benefits of loose typing.
Another use case is when you have a very large project and would like to turn on a rule but can't just enable it globally. The best example would be enabling strict mode for single folders at a time, fixing the errors and then moving on to the next one over time.
@JacobMillner If it's for separate directories, you should be able to do what you mentioned by adding a nested tsconfig.json
that extends from the root config and enables strict mode just for that directory and subdirectories.
@slikts That works perfectly thank you!
// tsconfig.json { "files": [], "references": [ { "path": "./tsconfig.src.json" }, { "path": "./tsconfig.test.json" }, ] }
@donaldpipowitch: After seeing this suggestion I've tried out a modified structure, which we're currently using it in our latest project - just sharing our findings. Maybe it can unblock others 🤷 (but your initial suggestion would definitely be an improvement in my book).
I'm also interested in feedback on potential problems this setup might cause.
(it's a bit long, so collapsed 🤷)
FYI: I haven't tried it, but it could be that this problem can now be solved by having “Solution Style” tsconfig.json Files.
Something like this:
// tsconfig.json { "files": [], "references": [ { "path": "./tsconfig.src.json" }, { "path": "./tsconfig.test.json" }, ] }
If that works it would probably make this issue obsolete.
FWIW - Have also tried this "Project references / build mode" approach. However, found that "tsc -b" does not produce the same output as running tsc in the subproject directory. This was the case when one of the sub-projects tsconfig.json (extending the base tsconfig.base.json) was set to override the module to commonjs - from ESM. The output from tsc -b was ESM, and the tsc from the subproject directory came out commonjs.
Hi guys. I'm not sure but maybe it can help anybody
In my situation, my project is Vue + Storybook
But I don't want to keep the storybook like part of a project, and I move storybooks packages/config/settings into subfolder
where .stories.ts stay like part of project
So, I need to add rule only for *.storybook.ts files
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": [
"src/**/*.stories.ts", // <-- only for storybook files
],
"compilerOptions": {
"composite": true,
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
],
"*": [
"./storybook/node_modules/*" // <-- add additional node_modules ['node_modules', 'storybook/node_modules']
]
}
}
}
But we don't have override rules for patterns for files, but can override include
and exclude
I need to add to include
all files "include": ["src/**/*"]
, because otherwise:
but I have collision rules, so we should fix in the reverse situation
tsconfig.json
{
"files": [],
"references": [
{
"path": "./tsconfig.config.json"
},
{
"path": "./tsconfig.app.json" // for application files
},
{
"path": "./tsconfig.vitest.json"
},
{
"path": "./tsconfig.storybook.json" // for only storybook files
}
]
}
tsconfig.app.json
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": [
"env.d.ts",
"src/**/*",
"src/**/*.vue"
],
"exclude": [
"src/**/__tests__/*",
"src/**/*.stories.ts" // without storybook files
],
"compilerOptions": {
"composite": true,
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
}
}
tsconfig.storybook.json
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": [
"src/**/*" // all files
],
"compilerOptions": {
"composite": true,
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
],
"*": [
"./storybook/node_modules/*" // additional node_modules
]
}
}
}
How it works
when we use any files but not *.stories.ts
then we apply tsconfig.app.json
when the previous pattern is wrong, and we use any file (without exclude) then we apply tsconfig.storybook.json
I think it is difficult for more combinations.
I expect from slow Microsoft Typescript team this feature:
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": [
"src/**/*.ts",
"src/**/*.vue"
],
"compilerOptions": {
"composite": true,
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
},
// Example 1
"overridesFiles": {
"src/**/*.stories.ts": {
// storybook
"paths": {
"*": [
"./storybook/node_modules/*"
]
}
},
"src/**/*.test.ts": {
// tests
"paths": {
"*": [
"./test/node_modules/*"
]
}
}
},
// Example 2
"overridesPattern": [
{
"patternFiles": [
"src/**/*.magic.ts",
"src/**/*.magic.vue"
],
"override": {
"paths": {
"*": [
"./test/node_modules/*"
]
}
}
}
]
}
or any other solution like https://eslint.org/docs/latest/user-guide/configuring/rules#using-configuration-files-1
P.s. the author of this issue gave a very cool example
we always need to make crutches, and we get answers after 3-4 years
@AndreiSoroka's answer ended up saving the day for me.
To clarify and simplify, a general tsconfig-dist.json
reference glob seems to need to be called first so it has to be listed last. For example, assume one of each file.test.ts
, file.stories.ts
, file.etc.ts
, file.ts
(dist) containing the following code that checks for noImplicitAny
:
// if noImplicityAny is set, (i) will error.
const fn = (i) => i;
fn('');
Assume one entry file tsconfig.json
pointing to one tsconfig-*.json
each matching their respective file above:
// tsconfig.json
{
...
"references": [
{ "path": "./tsconfig-test.json" },
{ "path": "./tsconfig-stories.json" },
{ "path": "./tsconfig-etc.json" },
{ "path": "./tsconfig-dist.json" } // appears last, called first
]
}
// tsconfig-dist.json
{
// called first
// (i) errors
...
"compilerOptions": { "noImplicitAny": true },
"include": ["./**/*"], "exclude": ["/**/*.test.*", "/**/*.stories.*", "/**/*.etc.*"]
}
// tsconfig-etc.json
{
// called second
// (i) does not error
...
"compilerOptions": { "noImplicitAny": false },
"include": ["./**/*"], "exclude": ["/**/*.test.*", "/**/*.stories.*"]
}
// tsconfig-test.json
{
// called third
// (i) errors
...
"compilerOptions": { "noImplicitAny": true },
"include": ["./**/*"], "exclude": ["/**/*.stories.*", "/**/*.etc.*"]
}
// tsconfig-stories.json
{
// called fourth
// (i) does not error
...
"compilerOptions": { "noImplicitAny": false },
"include": ["./**/*"], "exclude": ["/**/*.test.*", "/**/*.etc.*"]
}
The reason we have to include: ['./**/*']
and work off exclude: [...]
is because our stories and tests will include general dist files. If file.stories.ts
tries to import file.ts
but its tsconfig.json
is include: ['./**/*.stories.*']
, typescript will complain:
File '.../file.ts' is not listed within the file list of project '.../tsconfig-stories.json'.
So far this seems to work, but wouldn't one expect the order to be reversed? I agree with the general sentiment that this needs an explicit solution. Even something to the effect of an includeImports: []
to expand the scope of imports beyond include: []
while allowing those files to be excluded on first match would do it.
Hello! I recently finished working on a TypeScript plugin that allows overriding config for files and folders. It's still pretty rough, but it works. I would be happy to get feedback :) https://github.com/DiFuks/ts-overrides-plugin
Search Terms
Suggestion
It would be nice if
tsconfig.json
files would allow anoverrides
section which works in the same way as ESLint. Here I have just one config file in my root for all kind of files and use cases. TypeScript currently needs multipletsconfig.json
files.Use Cases
As far as I know editors like VS Code look for the nearest
tsconfig.json
for proper TypeScript support. This make it hard to properly type files which are used for different environments (e.g. source code vs tests vs storybook examples and so on) in the same directory, which seems to be a common convention nowadays (e.g.src/file.ts
,src/file.test.ts
,src/file.stories.ts
).Most people seem to ignore this fact which makes test globals like
describe
available in source code files.I once tweeted about this with a small example:
Examples
Checklist
My suggestion meets these guidelines: