The Compiler & Tooling
The compiler is the language
Section titled “The compiler is the language”Everything you learned about types is enforced by one program: the TypeScript compiler, tsc. But tsc does two jobs that are worth separating in your head — it checks your types and it emits JavaScript. Modern setups often split these: a bundler emits the JavaScript fast, and tsc checks the types separately.
Your tsconfig.json is where you decide how strict the checker is, which JavaScript features to target, how modules are resolved, and what (if anything) gets emitted. Getting this file right is the difference between TypeScript catching bugs and TypeScript quietly waving them through.
What this module covers
Section titled “What this module covers”| Lesson | What you’ll learn |
|---|---|
| tsconfig, deep | The high-value flags — strict and its family, target, module, and the strict-adjacent options |
| Modules & resolution | ESM vs CJS, and how tsc finds the files you import |
| Declaration files | What .d.ts files are, how to write them, and where @types comes from |
| Build & emit | tsc vs bundlers, isolatedModules, type-only imports, and project references |
The two jobs of tsc
Section titled “The two jobs of tsc”flowchart LR src["source .ts / .tsx"] --> tsc["tsc"] tsc -->|job 1| check["type-check report errors"] tsc -->|job 2| emit["emit .js and .d.ts (types erased)"] check --> ci["run in CI to catch bugs"] emit --> ship["run or bundle the JS"]
Keep these two jobs distinct and the whole toolchain makes sense. A bundler like esbuild can do job 2 in milliseconds because it just strips the types without understanding them — which means it will happily emit code that does not type-check. That is why the standard advice is: let the bundler emit, and run tsc --noEmit in CI to actually check. The rest of this module unpacks the config that controls both jobs.