Skip to content
TypeScript ts getting-started 4 min read

The TypeScript Compiler (tsc)

tsc is the official TypeScript compiler, and understanding what it does demystifies the whole toolchain. It performs two distinct jobs: type-checking (verifying your code obeys its types) and emitting (transpiling .ts to .js, optionally downleveling modern syntax to older targets). Modern projects often split these responsibilities — fast bundlers do the emitting while tsc is used purely as a type-checker. This page covers running tsc, the everyday flags, how it finds your tsconfig.json, and the type-check-only workflow that powers most real pipelines.

Two jobs: check and emit

Conceptually, tsc reads your source, builds a type model, reports any violations, and then writes JavaScript output. Either job can be run independently.

npx tsc            # check + emit, using tsconfig.json
npx tsc --noEmit   # check only, write nothing

Separating these is the key insight: you can let another tool produce the JavaScript and still rely on tsc for the authoritative type verdict.

Running with a tsconfig.json

When you run tsc with no file arguments, it looks for a tsconfig.json in the current directory (then upward) and compiles the whole project according to that config. This is the normal way to build a real project.

npx tsc                       # uses ./tsconfig.json
npx tsc --project ./tsconfig.build.json   # use a specific config

If you instead pass file names (tsc hello.ts), tsc ignores tsconfig.json entirely and uses only command-line flags — useful for one-off compiles but not for projects.

Everyday compiler flags

Most options live in tsconfig.json, but a handful are commonly passed on the command line. These override or supplement the config.

npx tsc --watch              # recompile on save
npx tsc --noEmit             # type-check only
npx tsc --outDir dist        # write output to dist/
npx tsc --target es2022      # JS version to emit
npx tsc --strict             # enable all strict checks
FlagPurpose
--watch / -wRecompile automatically on file changes
--noEmitType-check only; produce no .js files
--outDirDirectory for emitted JavaScript
--targetECMAScript version of the output
--moduleModule system of the output (e.g. esnext, commonjs)
--strictTurn on the full suite of strict type checks
--declarationAlso emit .d.ts type declaration files
--project / -pUse a specific tsconfig file

Type-check-only workflows

In modern stacks, a bundler (Vite, esbuild, SWC) or a runtime (tsx, Bun) handles transpilation because it is much faster. Those tools generally do not type-check. So the standard pattern is to add a separate script that runs tsc in no-emit mode.

// package.json
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "typecheck": "tsc --noEmit"
  }
}
npm run typecheck   # fails CI if any type error exists

This division keeps your dev loop fast while guaranteeing the type system is still enforced in CI.

Bundlers and tsx/esbuild transpile each file in isolation and skip cross-file type checking for speed. Never assume “it ran, so it’s typed correctly” — always include tsc --noEmit somewhere in your pipeline.

Incremental and project builds

For large codebases, tsc can cache results between runs and orchestrate multiple sub-projects, which speeds up repeated builds substantially.

npx tsc --incremental        # cache build info for faster rebuilds
npx tsc --build              # build project references in order

The --build (or -b) mode reads references in your tsconfig and compiles dependencies in the right order, only rebuilding what changed. Combined with --incremental, it makes monorepo-scale type-checking practical.

Reading compiler output

tsc errors include a stable code (like TS2345), the file and position, and a human-readable message. The codes are searchable and consistent across versions.

src/cart.ts:12:18 - error TS2345: Argument of type 'string' is not
assignable to parameter of type 'number'.

12   addItem(price, "2");
                    ~~~

Found 1 error in src/cart.ts:12

The caret/tilde underline points at the exact expression at fault, which makes diagnosing even complex generic errors far more approachable.

Best Practices

  • Run tsc against a tsconfig.json for projects; reserve file-argument compiles for one-offs.
  • Use tsc --noEmit as a dedicated typecheck script and run it in CI.
  • Let a fast bundler or tsx handle transpilation while tsc owns type verification.
  • Enable --incremental (and --build for monorepos) to speed up large rebuilds.
  • Emit .d.ts files with --declaration when publishing a library.
  • Search error codes like TS2345 when a message is unfamiliar — they are well documented.
Last updated June 29, 2026
Was this helpful?