9

Half the runtime bugs in our dashboard were "data is undefined but we still rendered the table." The types were { data?: T; loading: boolean; error?: string }, which lets you express nonsense like loading and error at the same time.

I wrote a prompt that forces the model to model fetch results as a discriminated union so the compiler makes the impossible states unrepresentable. The generated components got noticeably simpler because there was exactly one shape to render per state.

Still figuring out the cleanest way to fold optimistic updates into this without a fourth variant explosion. Ideas welcome.

THE PROMPT
Generate the TypeScript data-fetching layer for a React app using discriminated unions so impossible states are unrepresentable.

CONTRACT:
- Define `type Result<T, E = ApiError> = { status: 'idle' } | { status: 'loading' } | { status: 'success'; data: T } | { status: 'error'; error: E }`.
- `data` may ONLY exist on the success variant; `error` may ONLY exist on the error variant. Do not add optional fields to widen the union.
- Provide a `matchResult` helper that takes a Result and an object of handlers, one per status, and is exhaustive (rely on `never` in the default case so a missing handler is a compile error).
- Components must render by calling matchResult. Forbid `result.data?.` optional chaining at the call site.
- No `any`, no non-null assertions (`!`), no casting.

Deliver: types.ts, useResource.ts (a hook returning Result<T>), and one example component. End by showing that adding a new status without updating matchResult produces a type error, and paste that error.
for optimistic updates i keep the union at four states but add an `optimistic: boolean` only inside the success variant. no new top-level state, rollback just flips it back to the server value.api_ana 2 months ago
the `never` exhaustiveness check is the whole game. i now refuse any state machine that doesn't compile-error when i add a case. saved me during a refactor last week.nullpointer 2 months ago
add a comment

0 Answers

Your Answer