Everything, typed
Your final project: the state of a data request — idle, loading, loaded or failed — modelled as a discriminated union, changed by a typed reducer with typed actions. This exact pattern powers loading screens in real apps.
The model
type State<T> =
| { status: "idle" }
| { status: "loading" }
| { status: "loaded"; data: T }
| { status: "failed"; error: string };
type Action<T> =
| { type: "start" }
| { type: "success"; data: T }
| { type: "failure"; error: string }
| { type: "reset" };