TypeScript's types exist only during checking. When tsc emits JavaScript it removes every construct that exists purely for the type system:
- annotations and return types,
interfaceandtypedeclarations, generics and their arguments; as,satisfies,!and overload signatures;declarestatements,abstractandprivate/readonly/overridemodifiers,import type/export type.
Erasure is a stated design goal: the Design Goals page lists "impose no runtime overhead" and "use a consistent, fully erasable, structural type system", and lists "add or rely on run-time type information" as a non-goal.
Consequences I would name in an interview:
- A type is not a value.
x instanceof User,typeof Userin a value position, orv === Idfor an interface or alias is error TS2693. There is nothing at runtime to refer to. - Types do not validate.
JSON.parse(text) as Usercompiles toJSON.parse(text). If the payload hasid: "7", the code runs with a string where the type saysnumber, and fails later, away from the cause. - Overloads and generics do not change runtime behavior. There is one JavaScript function, so you cannot dispatch on a type parameter.
So the type system describes data you already trust, and anything that crosses a trust boundary (network, JSON.parse, localStorage, process.env, user input) must be checked with runtime code. Two options: a schema library (Zod and similar), where one definition gives both a validator and, through inference, the static type; or a user-defined type guard you write yourself. A guard is a promise, not a check: TypeScript believes the v is User return type without looking at the body.
A few constructs are not erased because they need generated code (enums, namespaces with values, parameter properties). That is the subject of erasableSyntaxOnly.