tsconfig.json beyond the basics
Module 00 covered the five options every project sets on day one — target, module, strict, esModuleInterop, skipLibCheck. Real projects grow a few more, for output layout, generated declarations, and keeping the codebase from quietly accumulating dead code.
| Option | What it does |
|---|---|
lib | Which built-in type definitions are available — ["ES2020", "DOM"] adds browser globals like window; a Node-only project omits DOM so using it is a compile error, not a runtime surprise. |
outDir / rootDir | Where compiled .js goes, and which folder is treated as the source root — rootDir: "src", outDir: "dist" mirrors your source tree under dist/ instead of scattering .js next to every .ts. |
declaration | Emits a matching .d.ts next to every compiled .js — required for anything you publish as a package (Module 09). |
declarationMap | A source map for the .d.ts itself — lets an editor "go to definition" straight into your original .ts, not the generated declaration. |
sourceMap | Emits .js.map files so a debugger shows your original TypeScript lines and variable names, not the compiled JavaScript. |
noUnusedLocals / noUnusedParameters | Errors on a declared-but-never-read local variable, or an unused function parameter — dead code the checker can catch that has nothing to do with types. |
noImplicitReturns | Errors if a function has a branch that falls through without an explicit return while other branches do return — a frequent bug in a function with several early-return conditions. |
composite / references | Marks a package as buildable in isolation and lists which other packages it depends on — the basis for project references, below. |
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"rootDir": "src",
"outDir": "dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true
},
"include": ["src"]
}shared library, an api, a web app) can wire each package's tsconfig with "composite": true and list its dependencies under "references". A root tsconfig then references all of them, and tsc -b ("build mode") compiles only the packages that changed, in dependency order — instead of one giant program checking everything, every time.{
"compilerOptions": {
"composite": true,
"rootDir": "src",
"outDir": "dist"
},
"references": [
{ "path": "../shared" }
]
}Mid-levelWhat problem do TypeScript project references solve, and when would you reach for them?
In a monorepo with several TypeScript packages that depend on each other, a single flat tsconfig re-checks the entire dependency graph on every build, even for a change in one leaf package. Project references (composite: true plus a references list, built with tsc -b) let the compiler build each package in isolation, in dependency order, and skip packages whose inputs have not changed — turning a full rebuild into an incremental one. It is worth the setup cost once a repo has more than a couple of internal packages that import each other; for a single-package app it is unnecessary complexity.
