Here is the directory structure:
root/
tsconfig.json
ts/
index.ts
index.spec.ts
I want separate tsconfig.json settings for spec files and production code. For example, I want "noImplicitAny": true
for my production code and "noImplicitAny": false
for my test code.
I also want Visual Studio Code to be in sync with tsc
, eslint
, etc. In other words, if Visual Studio Code reports an error, I want my build process to report the same error, and vice versa.
Although I've found solutions that get me 90% of the way, I've yet to find a solution that completely works. Usually, it's VS Code reporting errors that aren't actually there.
How do I meet all these requirements?
I realized after the fact that there were issues with my original answer. For one, the tsconfig.spec.json
did not have composite
set. Technically, that's an error, but it's only reported if another tsconfig references it AND that other tsconfig includes
> 0 files.
Perhaps even more importantly, the tsconfig.spec.json
should have referenced the tsconfig.src.json
. That didn't appear as an error because the files in my previous example didn't import across reference boundaries.
I'm keeping the first answer around for prosperity. It's a good (bad?) example demonstrating how your tsconfigs can be error-free and build, even when they're in an invalid state. (The irony isn't lost on me.)
Here is a correct example. I use // @ts-ignore
to ignore compile time errors that should (and do) occur; they prove tsconfig.src.json
files can't import tsconfig.spec.json
files.
.
├── package.json
├── src1/
│ └── subdir1/
│ ├── foo.spec.ts
│ └── foo.ts
├── src2/
│ └── subdir2/
│ ├── bar.spec.ts
│ └── bar.ts
├── tsconfig.json
├── tsconfig.spec.json
└── tsconfig.src.json
{
"name": "project-reference-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "tsc --build"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"typescript": "^5.1.6"
}
}
import { PROD_FOO } from './foo'
console.log(PROD_FOO);
export const TEST_FOO = 1;
// @ts-ignore File './src1/subdir1/foo.spec.ts' is not listed within the file list of project './tsconfig.src.json'. Projects must list all files or use an 'include' pattern. ts(6307)
import { TEST_FOO } from './foo.spec'
console.log(TEST_FOO);
export const PROD_FOO = 1;
import { PROD_BAR } from './bar'
console.log(PROD_BAR);
export const TEST_BAR = 1;
// @ts-ignore File './src1/subdir1/bar.spec.ts' is not listed within the file list of project './tsconfig.src.json'. Projects must list all files or use an 'include' pattern. ts(6307)
import { TEST_BAR } from './bar.spec'
console.log(TEST_BAR);
export const PROD_BAR = 1;
{
"compilerOptions": {
"target": "es2018",
"module": "es2015",
"lib": [
"es2020",
"dom",
"DOM.Iterable"
],
"allowJs": false,
"sourceMap": true,
"outDir": "tscbuild",
"importHelpers": true,
"downlevelIteration": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"alwaysStrict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"noErrorTruncation": true,
},
"references": [
{
"path": "./tsconfig.src.json"
},
{
"path": "./tsconfig.spec.json"
},
],
"include": [],
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"composite": true,
"noEmit": true,
"noImplicitAny": false,
"module": "commonjs"
},
"include": [
"./src*/**/*.spec.ts",
],
"references": [
{
"path": "./tsconfig.src.json"
}
]
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"composite": true,
},
"include": [
"./src*/**/*.ts",
],
"exclude": [
"./src*/**/*.spec.ts",
],
}