TypeScript's type system is expressive enough to encode business rules directly into your types — if you use it correctly. Most TypeScript codebases settle for basic type annotations when they could be eliminating entire classes of bugs at the type level.
Make Impossible States Unrepresentable
The most powerful TypeScript technique is designing types so that invalid states simply cannot be expressed. If your code compiles, the invalid state cannot occur — no defensive checks needed at runtime.
Branded Types for Domain Safety
Primitive obsession — using string or number for everything — is a silent killer. A userId and an orderId are both strings, but they should never be interchangeable. Branded types enforce this at the type level with zero runtime cost.
Pair branded types with a small factory function (e.g. asUserId(raw: string): UserId) at your system boundaries — API responses, database queries — to keep the casting contained.
Template Literal Types for String Validation
TypeScript's template literal types let you encode string shape constraints directly in the type system. You can enforce that an API route starts with '/', that a CSS variable starts with '--', or that an event name follows a 'namespace:event' pattern — all at compile time.