Knowing what TypeScript does (and does not do) at runtime shapes every decision you make with it.
TypeScript is a superset of JavaScript: every JavaScript program is syntactically valid TypeScript, and TypeScript adds a way to describe the shapes of values — which properties an object has, what a function takes and returns. A checker reads those descriptions and reports mistakes before the code ever runs.
The key mental model: types are erased. The compiler checks your code, then strips the annotations and emits plain JavaScript. Nothing about types survives at runtime — there is no type information to inspect, no runtime validation of function arguments, no performance change. If data comes from JSON.parse or a network call, TypeScript only knows what you tell it; it cannot verify it.
What you get in exchange:
- Errors caught early: typos in property names, calling something that might be
undefined, passing a string where a number is expected. - Editor intelligence: autocomplete, go-to-definition, safe rename and inline docs all come from the same type information.
- Documentation that can't go stale: a function signature tells the next reader exactly what it accepts.
- Confident refactoring: change a type and the compiler lists every place that needs updating.
TypeScript is also gradual. You can rename a .js file to .ts, fix a few errors and keep going, and strictness can be raised over time. Its type system is structural: two types are compatible if their shapes match, regardless of their names, which fits how JavaScript code is actually written.
A type error does not stop JavaScript being emitted by default — the checker and the emitter are separate jobs, and many projects let a bundler or runtime strip types while tsc only checks.
Example
// The TypeScript you write:
function greet(user: { name: string; age?: number }): string {
return `Hello, ${user.name}`;
}
greet({ name: "Ada" });
// @ts-expect-error -- 'nme' does not exist; did you mean 'name'?
greet({ nme: "Ada" });
// The JavaScript that runs (types erased):
// function greet(user) {
// return `Hello, ${user.name}`;
// }Remember
- TypeScript = JavaScript + static types checked before runtime
- Types are erased: no runtime checks, no runtime cost
- Typing is structural: compatible shapes, not matching names
Watch out for
- Assuming TypeScript validates external data (API responses, JSON) at runtime — it does not.