TypeScript earns its keep at the boundaries of a system — where data crosses from one trust domain into another. In the warm middle, the returns fall off fast.
Types at the boundary
Parse, don't validate. Turn untrusted input into a precise type once, at the edge, and let the rest of the code assume it is well-formed. A schema at the door is worth a hundred defensive checks scattered through the core.
Where they pay off
Public APIs, database rows, env vars, and anything touching the network deserve exact types. These are the places a wrong shape becomes a production incident rather than a quick local error.
Where they get in the way
Chasing total type coverage on internal glue code mostly buys you generics nobody can read. When the type is harder to understand than the code it describes, you have overshot — loosen it and move on.
