The compiler and runtime
Understand type erasure
Know which TypeScript features disappear and why a type cannot be inspected like a JavaScript value.
TypeScript removes every type-only piece of syntax when it emits JavaScript. Let’s watch it happen.
type User = { name: string }
function greet(user: User) {
return `Hello ${user.name}`
}
Compile that with npx tsc and open the output:
function greet(user) {
return `Hello ${user.name}`
}
The function survived. The User alias and the parameter annotation did not. They were not turned into a runtime registry or a hidden check. They are gone.
This is type erasure. Interfaces, type aliases, annotations, generics, and type-only imports exist for the checker and for your editor. By the time the code runs, none of them exist anywhere, so JavaScript cannot inspect them.
Types are not values
That is why this cannot work:
value instanceof User
The compiler rejects it with a very literal message:
'User' only refers to a type, but is being used as a value here.
User is not a runtime value. instanceof is a JavaScript operator, and it needs a constructor function on its right side. After erasure there is nothing there. The same goes for ideas like typeof value === User, or looping over “the properties of a type”. The runtime has no types to consult.
When you need a runtime decision, use something that survives compilation. Check object properties with in, use a real class with instanceof, or parse the value with a schema. A class works because a class declaration is both a type and a value: it emits a constructor function that exists at runtime.
What erasure gives you
Erasure means types add zero runtime cost. The emitted program is ordinary JavaScript, exactly as fast as the untyped version, with no library shipped to your users. You can annotate everything and pay nothing at runtime.
What erasure costs you
The flip side is that types never validate data. Annotating a network response as User changes nothing about the bytes that arrive. The annotation is checked against your code, never against the data. If the server sends { "name": 42 }, your User says string, and the program runs anyway with a number where a string should be.
Keeping “compile-time claim” and “runtime fact” separate in your head is one of the most useful mental models in this whole course. The next lessons are about the runtime side: declaration files that describe JavaScript to the checker, and validation that turns unknown data into a trusted type.
Try this: compile the example above, open the .js file, and list every TypeScript-only part that disappeared. Then add a generic function and check that the angle brackets vanish too.
Lesson completed