-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow overrides in tsconfig #33407
Comments
Maybe they shouldn't be mixing test and source files? The |
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.) |
It's called "colocating" and it's a common pattern in the JavaScript world. Exhibit A:
https://islovely.co/posts/colocating-unit-tests Exhibit B:
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: |
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 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 |
One pretty common use case I think would be in mono-repository architectures, where you have multiple packages all having their own |
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 |
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 |
@slikts That works perfectly thank you! |
@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. Click here to see full structure & findingsInto: We're using Vue3 (so adjust accordingly for other libs), with unit-tests running in Jest & e2e-tests + component-tests running in Cypress.
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"baseUrl": ".",
"moduleResolution": "node",
"esModuleInterop": true,
"useDefineForClassFields": true,
"resolveJsonModule": true,
"sourceMap": true,
"lib": ["esnext", "dom"],
"paths": {
"@/*": ["./src/*"]
}
},
"include": [
"src/**/*.ts",
"src/**/*.vue",
"src/shims-vue.d.ts"
],
"exclude": [
"node_modules/cypress/types",
"node_modules/@types/jest",
"src/**/*.ct.ts",
"src/**/*.e2e.ts",
"src/**/*.unit.ts"
],
"references": [
{ "path": "./tsconfig.jest.json" },
{ "path": "./tsconfig.cypress.json" }
]
}
{
"extends": "./tsconfig",
"compilerOptions": {
"composite": true,
"types": ["cypress"]
},
"include": [
"src/**/*.ts",
"src/**/*.vue",
"e2e/**/*.e2e.ts",
"test-data/**/*.json",
"src/shims-vue.d.ts"
],
"exclude": [
"node_modules/@types/jest",
"src/**/*.unit.ts"
]
}
{
"extends": "./tsconfig",
"compilerOptions": {
"composite": true,
"types": ["jest"]
},
"include": [
"src/**/*.ts",
"src/**/*.vue",
"test-data/**/*.json",
"src/shims-vue.d.ts"
],
"exclude": [
"node_modules/cypress/types",
"src/**/*.ct.ts",
"src/**/*.e2e.ts",
]
} Now this fixes most problems... BUT, some tools in our tool-chain (for type-checks) does not yet support "incremental mode", triggered by defining Pre script const fs = require('fs');
const tsconfig = require('../tsconfig.json');
// remove references before creating temp tsconfig.prod.json
delete tsconfig.references;
fs.writeFileSync('tsconfig.prod.json', JSON.stringify(tsconfig), 'utf8'); Post script const fs = require('fs');
// cleanup after temp-tsconfig.prod.json-create.js
if (fs.existsSync('tsconfig.prod.json')) {
fs.rmSync('tsconfig.prod.json');
} @donaldpipowitch: thank for the suggestion. (it's a bit long, so collapsed 🤷) |
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 ProblemIn 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 I need to add to Solutiontsconfig.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 I think it is difficult for more combinations. What I expectedI 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 // if noImplicityAny is set, (i) will error.
const fn = (i) => i;
fn(''); Assume one entry file // 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
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 |
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:
The text was updated successfully, but these errors were encountered: