Type-Safe Frontend Code, in Practice
Static typing in frontend code is often adopted for autocomplete and kept for refactoring. But the real return comes from a shift in habit: using types to describe what is actually true, instead of what is convenient to write.
Type the boundaries hardest
Bugs enter at the edges — network responses, URL parameters, storage, third-party widgets. Inside your code the compiler tracks everything; at the edges it trusts whatever you assert. Validate incoming data at runtime, once, at the boundary, and derive the static type from that validator so the two can never drift apart.
Model states, not fields
A record full of optional fields is a lie: it claims every combination is possible. Interfaces live in states — idle, loading, loaded, failed — and a discriminated union with one variant per state lets the compiler prove you handled each one. The switch statement it forces on you is the UI you were going to write anyway.
Make illegal values unrepresentable
Prefer a union of known strings to a bare string, a branded id to a raw number, a non-empty array type where emptiness is a bug. Each narrowing deletes a category of test you no longer need to write.
Treat assertions as debt
Every non-null assertion and type cast is a place where you overruled the compiler. Sometimes you know better — but each one is invisible to future refactors, which is exactly where they detonate. Keep them rare, commented, and concentrated at the boundaries where validation already happened.
Let inference do the typing
Annotate function signatures and exported values; let everything inside be inferred. Code that repeats what inference already knows is noise that goes stale. The goal is not more type syntax — it is more truth per line.
Types are documentation the compiler reads. Written this way, they are documentation that cannot lie.