Most React devs handle API state like this: isLoading, isError, data, three separate booleans that can contradict each other. Loading = true AND error = true at the same time? Shouldn't happen, but nothing prevents it. Discriminated unions fix this cleanly: type AsyncState<T> = | { status: 'idle' } | { status: 'loading' } | { status: 'success'; data: T } | { status: 'error'; error: Error } Now TypeScript enforces that you handle each case. Inside the 'success' branch, state.data is always defined. No optional chaining, no null checks. The real win: when you switch on state.status, TypeScript narrows automatically. No more wondering "is data null because it's loading, or because it failed?" It's a small change that eliminates a whole class of bugs and makes component logic self-documenting. What state patterns are you reaching for in your React projects right now? #TypeScript #React #WebDevelopment
This TypeScript modeling fits Vue as well. Great insight
Great info!
This pattern changed how I write every component. I used to have the classic trio - isLoading, isError, data - and inevitably hit that impossible state where loading is true but data also exists from a previous fetch. Discriminated unions killed that entire class of bugs. I take it one step further - I pair this pattern with a custom useAsync hook that returns the discriminated union directly, so every component in the codebase handles async state the same way. No more one component checking if(data) while another checks if(!isLoading && !isError). Consistency across 50+ components without a single meeting about “how we handle loading states.” TypeScript does the enforcing for you.