Introduction
TypeScript adds a type system on top of JavaScript, then compiles down to plain JavaScript that runs anywhere JavaScript already does. The types exist purely to help you and your editor catch mistakes before the code runs — by the time it's compiled, every type annotation is gone.
A plain JavaScript problem
In JavaScript, nothing stops you from calling a function with the wrong kind of value. The mistake only shows up once the code actually runs:
function greet(name) {
return "Hello, " + name.toUpperCase() + "!";
}
console.log(greet(42));
Uncaught TypeError: name.toUpperCase is not a function
Nothing about the code above looked wrong until it ran — 42 is a valid argument as far as JavaScript is concerned, right up until .toUpperCase() is called on it.
The same code in TypeScript
Adding a type annotation to the parameter tells the compiler exactly what's allowed, so the mistake is caught before the program ever runs:
function greet(name: string) { return "Hello, " + name.toUpperCase() + "!"; } console.log(greet(42));
greet.ts:5:19 - error TS2345: Argument of type 'number' is not
assignable to parameter of type 'string'.
5 console.log(greet(42));
~~name: string is a type annotation — it tells the compiler that name must always be a string. Running tsc greet.ts catches the mismatch immediately and refuses to produce output until it's fixed, instead of letting it become a runtime crash.
Compiling to JavaScript
Once the types check out, tsc strips every type annotation and produces ordinary JavaScript:
function greet(name: string): string { return "Hello, " + name.toUpperCase() + "!"; } console.log(greet("maya"));
function greet(name) {
return "Hello, " + name.toUpperCase() + "!";
}
console.log(greet("maya"));Hello, MAYA!
tsc compiles your code successfully, that particular category of mistake is already ruled out. It also means TypeScript can't catch a type mismatch coming from outside your code, like a value from an API response — you're on your own for validating that.