CodeOath
← All posts
TypeScript75 min total · 21 parts

TypeScript Fundamentals: Types, Interfaces, Generics, and Why It Catches Bugs Before Runtime

Contents — Part 2 of 21: The Compiler and Type Erasure
Part 2 of 21 · ~1 min

The Compiler and Type Erasure

TypeScript code is never executed directly. The TypeScript compiler (tsc, or the equivalent built into your bundler/transpiler — Babel, esbuild, SWC) reads your .ts/.tsx files, checks them against the type rules, and then strips every type annotation out entirely, emitting plain JavaScript:

// input.ts
function add(a: number, b: number): number {
  return a + b;
}

// output.js — every type annotation is simply gone
function add(a, b) {
  return a + b;
}

This is called type erasure, and it has a consequence that trips people up constantly: types have zero effect at runtime. They cannot be checked, logged, or branched on once the code is running — only source-level tooling (the compiler, your editor) ever sees them.

interface User { name: string; age: number; }

function greet(user: User) {
  console.log(typeof user); // "object" — there is no runtime trace of "User" at all
}

A second consequence: most type errors don't stop your code from running. By default, tsc still emits JavaScript even when it reports errors — the errors are warnings about static analysis, not a hard gate, unless your build pipeline is configured to fail on them (which almost every real project does, usually via tsc --noEmit in CI, or a bundler set to fail on type errors). Understanding that TypeScript is "JavaScript plus a checker that gets deleted" explains almost every surprising thing about how the two interact, including why you still need runtime validation for anything crossing a real boundary (covered later, in the section on unknown).