A few weeks ago I was reviewing a pull request where a component crashed in production with the classic Cannot read properties of undefined. The bug wasn't a typo or a missing null check—it was something more subtle. The type allowed a combination of values that should never have existed in the first place. The data was loading: false, error: null, and data: undefined all at once, and nobody could tell me what that state was supposed to mean.

That's the trap of modeling state with a bag of optional properties. TypeScript happily lets you construct nonsense, and you find out at runtime. Discriminated unions fix this at the type level: you describe the states that can exist, and the compiler makes every other combination a compile error. Once I started reaching for them, an entire category of bugs disappeared from my code.

The Problem: Optional Properties That Lie

Here's the shape I see constantly. Imagine a hook that fetches a user:

interface UserState {