On the right is a TypeScript file with a checker watching it. Break it: change 42 to "42", or pass a number to greet. The checker complains.
Place your bet before compiling. What does the browser receive from this file?
Deleted. Every : number, every interface, every <T> is erased. What ships is plain JavaScript that looks like you never used TypeScript at all.
press Compile →
It's a spell-checker that runs before your code does, then gets out of the way. Node doesn't know it exists. The browser doesn't know it exists. The database certainly doesn't.
So when a type is wrong at runtime, say an API returns a string where you declared a number, TypeScript can't help you. It checked what you said, not what arrived. That's what zod is for: checking real data where it enters your app, while it's running.
This is the part that's different from Java or C#: TypeScript doesn't care what an object is called, only what it has. Extra fields are fine. Missing or wrong ones aren't.
Click each object to check it against User.
type User = { id: number; name: string; email?: string; // ? = optional };
Structural typing: duck typing with a spell-checker.
Array<T> is a box whose label you fill in later. Array<User> is a box of users. Promise<User> is a promise that will eventually contain a user.
Pick a contents label and watch it flow through every box that uses it. That's all T is: a placeholder that gets filled in once and applied everywhere.
async function first<T>(items: T[]): Promise<T> { return items[0]; } const u = await first(users); // u is User — inferred, no annotation
When you rename a field, every place that uses it lights up red. When you call a function, the editor tells you what it wants. When a package updates and changes its API, you find out at compile time, not from a user.
For a person vibe-coding, this is the quiet reason things work at all: the model gets the same red squiggles you do, and fixes them before you see them. Turn TypeScript off and you'll find out how much of the guidance was coming from it.
| JavaScript | TypeScript | |
|---|---|---|
Rename user.name → user.fullName | Find and replace, hope | Every stale use is an error, listed |
Call sendEmail(to, subject) | Check the docs, or the source | Editor shows the signature as you type |
API returns null sometimes | Crash in production | string | null forces you to handle it |
| Cost | none | Annotations, a build step, occasional fights |
That someone is the bundler. It's the least-understood tool in the stack and the one that decides how fast npm run dev feels.