tsconfig.json and Compiler Options

intermediate
12 min

tsconfig.json and Compiler Options

The tsconfig.json file is the control center of every TypeScript project. It tells the compiler which files to include, how strictly to check them, what JavaScript to emit, and how to resolve modules. Understanding a dozen key options takes you from copy-pasting configs to confidently tuning your own.

Creating and Structuring the File

Generate a starter config with npx tsc --init. A practical modern configuration looks like this:

json
{ "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "strict": true, "outDir": "./dist", "rootDir": "./src", "sourceMap": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] }

include and exclude control which files are part of the project; everything else lives under compilerOptions.

Output Options: target, module, outDir

  • target sets the JavaScript version of the emitted code. ES2022 is safe for current browsers and Node.js; older targets transpile modern syntax down.
  • module sets the module system of the output. Use NodeNext for Node.js projects (it respects package.json "type"), or ESNext when a bundler like Vite or esbuild handles modules.
  • outDir and rootDir map your src/ tree to a dist/ tree, keeping compiled output out of your source folders.
  • sourceMap emits .map files so debuggers and stack traces point at your TypeScript, not the generated JavaScript.

The strict Family: Non-Negotiable

"strict": true enables a bundle of checks, and every serious project should turn it on from day one:

  • strictNullChecksnull and undefined must be handled explicitly. The single most valuable flag.
  • noImplicitAny — parameters and variables cannot silently become any.
  • strictFunctionTypes, strictBindCallApply — sound checking of function assignments and .call/.apply.
  • strictPropertyInitialization — class fields must be initialized.

Retrofitting strictness onto a large lax codebase is painful; starting strict is nearly free. Worth adding on top of strict:

json
"noUncheckedIndexedAccess": true, "noImplicitOverride": true, "noFallthroughCasesInSwitch": true

noUncheckedIndexedAccess makes array[i] return T | undefined, forcing bounds thinking — strict but bug-catching.

Interop and Ergonomics

  • esModuleInterop smooths importing CommonJS packages with ES import syntax; virtually every project wants it.
  • skipLibCheck skips type-checking .d.ts files in node_modules, dramatically speeding up builds and avoiding errors in third-party types you cannot fix.
  • resolveJsonModule lets you import config from "./config.json" with types.
  • lib declares which built-in APIs exist, e.g. ["ES2022", "DOM"] for browser code — drop "DOM" for pure Node projects.

Path Aliases

Tired of ../../../utils? Map clean prefixes to folders:

json
"baseUrl": ".", "paths": { "@/*": ["src/*"] }

Then import { log } from "@/utils/log". Note that paths only affects type checking — your bundler or runtime needs a matching alias configuration.

Project Setups You Will Meet

  • Bundler apps (Vite, Next.js): the bundler compiles; tsc is used with "noEmit": true purely as a type checker in CI.
  • Libraries: enable "declaration": true to emit .d.ts files so consumers get your types.
  • Monorepos: a base tsconfig.base.json is shared via "extends", and project references ("composite": true) enable fast incremental builds across packages.

Key Takeaways

  • tsconfig.json defines project files, checking strictness, and emit format in one place.
  • Always enable strict; consider noUncheckedIndexedAccess for maximum safety.
  • target controls emitted syntax; module/moduleResolution should be NodeNext for Node or ESNext + bundler.
  • esModuleInterop and skipLibCheck are near-universal quality-of-life settings.
  • Use extends to share configs and noEmit when a bundler owns compilation.

Next lesson: Using TypeScript with React and Node.js — applying everything in real frameworks.

tsconfig.json and Compiler Options - TypeScript | CodeYourCraft | CodeYourCraft