The existing piece on static versus dynamic typing in this category covers the general distinction between checking types before a program runs versus while it runs. TypeScript's specific, sometimes-surprising angle on that distinction: despite being a statically typed language, none of its type information is actually present once the code runs at all.

TypeScript compiles down to plain JavaScript, and its compiler's actual job with respect to types is to check them thoroughly at compile time and then erase every trace of them -- every type annotation, interface, and generic parameter is stripped out entirely, not compiled into some lightweight runtime check. The JavaScript that actually ships and runs is functionally identical to what you'd get writing the same logic directly in JavaScript with no type annotations at all.

The practical consequence shows up specifically at a program's actual boundaries with the outside world: parsing JSON from an API response, reading a value from an untyped third-party library, or using an explicit type assertion (as SomeType) to tell the compiler "trust me" about a value's shape. In every one of those cases, TypeScript happily lets the code compile based on the type it was told to assume -- but if the real value at runtime doesn't actually match that shape, nothing catches the mismatch, because the type-checking machinery that would have caught it doesn't exist anymore once the code is actually running.

The only real defense against that gap is code that performs an actual runtime check -- a typeof or instanceof test, or a dedicated validation library that inspects a real value's actual shape at runtime and throws or reports an error if it doesn't match -- because those checks compile to genuine, surviving JavaScript, unlike a type annotation that the compiler discards. A type annotation describes what a value should be; a runtime check verifies what a value actually is, and only one of those two survives compilation.

This is the debugging implication worth internalizing: when a bug shows up in production involving a value that "shouldn't" have the wrong type according to its annotations, the type annotation was never actually protecting anything at runtime in the first place -- the real bug is almost always at a boundary where an assumption about incoming data's shape was never backed by an actual runtime check.