tsc and tsconfig.json

TypeScript · Essentials · 12 min

Every TypeScript project is driven by a tsconfig.json; knowing its core options saves hours of confusing errors.

The compiler is the typescript npm package, installed per project: npm install --save-dev typescript, then run it with npx tsc. npx tsc --init writes a starter tsconfig.json, the file that marks the root of a project and tells tsc what to compile and how.

The options you will touch most:

  • include / exclude / files: which source files belong to the project (e.g. ["src"]).
  • target: the JavaScript version to emit (ES2022, ESNext...). Newer syntax is down-levelled for older targets.
  • lib: which built-in APIs exist for type checking — ES2023, DOM and so on. It does not polyfill anything.
  • module and moduleResolution: how imports are written and resolved. Use "nodenext" for code run directly by Node, or "preserve" with "bundler" resolution when Vite, esbuild or webpack bundles your code.
  • outDir / rootDir: where compiled .js goes and which folder mirrors into it.
  • strict: turns on the whole family of strict checks. Always enable it in new projects.
  • noEmit: check only, write nothing — common when a bundler or runtime handles the type stripping.

Useful commands: tsc (build the project found in the current folder), tsc --noEmit (type-check, e.g. in CI), tsc --watch (rebuild on change), and tsc -p path/to/tsconfig.json.

Many toolchains never use tsc to produce JavaScript: esbuild, swc, Vite, Bun, Deno and recent Node versions simply strip the types without checking them. That is fast, but it means type errors only surface when you run tsc --noEmit (or your editor) — make that a step in CI.

Note that running tsc file.ts with a file name ignores tsconfig.json entirely and uses defaults, which surprises almost everyone once.

Example

{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2023", "DOM"],
    "module": "nodenext",
    "moduleResolution": "nodenext",
    "rootDir": "src",
    "outDir": "dist",
    "strict": true,
    "skipLibCheck": true,
    "sourceMap": true
  },
  "include": ["src"]
}

Remember

  • npx tsc --init creates tsconfig.json; npx tsc builds the project it describes
  • strict: true in every new project
  • Bundlers often strip types without checking: run tsc --noEmit in CI
  • lib controls which APIs type-check; it adds no polyfills

Watch out for

  • Running tsc somefile.ts and wondering why your tsconfig settings are ignored.

Check yourself

  1. Your project builds with esbuild, which strips types. Where will type errors be reported?
  2. You set target to ES5 and use Array.prototype.includes. What does tsc do about the missing method on old browsers?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: www.typescriptlang.org/docs/handbook/tsconfig-json.html