tsconfig mastery
Most tsconfig confusion comes from treating it as boilerplate to copy. The file makes a handful of decisions that shape how your code compiles, resolves modules, and gets checked; understand those and the rest follows.
Method
- Set strictness first, and mean it.
"strict": trueplus the extra checks you want (noUncheckedIndexedAccess,noImplicitOverride): this is the flag group that determines whether TypeScript is helping you (see typescript-strictness). Everything else is plumbing by comparison. - Match
moduleandmoduleResolutionto your runtime and bundler. This is where most errors come from. Modern setups use"module": "ESNext"(or"NodeNext"for Node without a bundler) with"moduleResolution": "Bundler"or"NodeNext"accordingly. A mismatch produces the "cannot find module" and extension-required errors that waste hours (see js-modules for the ESM/CJS reality underneath). - Set
targetandlibto your real environment.targetdetermines the JS features downleveled;libdetermines which APIs the compiler believes exist. Targeting too low bloats output with polyfilled helpers; too high ships syntax the runtime cannot run. Set both to what you actually deploy to (a modern Node version, or via the bundler for browsers). - Separate typecheck from build. Bundlers (Vite, esbuild, tsup) do
the transpilation;
tscdoes the typechecking. A common clean setup:"noEmit": truefor the check config, and let the bundler emit. Runtsc --noEmitin CI as the type gate (see linting-setup) even when it never produces output. - Use project references for monorepos. In a workspace,
"references"plus"composite": truelet packages typecheck and build incrementally in dependency order (see monorepo-workspaces). Without them, a large monorepo re-checks everything on every change. - Enable the ergonomic flags.
"esModuleInterop": trueand"skipLibCheck": true(skip checking.d.tsof dependencies: faster builds, and their type errors are not yours to fix),"forceConsistentCasingInFileNames": true(catches the case-mismatch bug that only bites on Linux CI), and"paths"for import aliases (kept in sync with the bundler's aliases).
Boundaries
- tsconfig controls type checking and, optionally, emit; it does not bundle, minify, or run your code (that is the bundler and runtime's job; see js-tooling-selection).
- Copied configs from tutorials mix settings for different runtimes and
eras; a
module/moduleResolutionpair from a 2019 blog post is the usual root of module-resolution pain. Set them for your stack. skipLibChecktrades some safety (it skips your dependencies' type correctness) for build speed and sanity; it is the pragmatic default, but know that it is a tradeoff.