Promise Machines
A promise machine wraps an async function and tracks its lifecycle as four discrete states. You get loading / success / error states for free — no flags to juggle, no stale data on the next request, full type inference on the result and error.
The four states
Section titled “The four states”Every promise machine starts in Idle and moves through this graph:
- Idle — before you call
execute - Pending — call in flight; state carries the
promiseand theparamsyou called it with - Resolved — call succeeded; state carries
result - Rejected — call failed; state carries
error
Calling execute again returns the machine to Pending and the cycle repeats.
Creating one
Section titled “Creating one”Pass any async function. The return type and parameter types propagate everywhere — state.data on Resolved is typed, params on Pending is typed.
import { createPromiseMachine } from "matchina";
const fetcher = createPromiseMachine(async (url: string) => { const response = await fetch(url); if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json();});Driving it
Section titled “Driving it”// Kick off the callawait fetcher.execute("/api/user");
// Or fire-and-forget — read state laterfetcher.execute("/api/user");
// Pattern-match the current stateconst view = fetcher.getState().match({ Idle: () => "Click load to fetch", Pending: ({ params }) => `Loading ${params[0]}…`, Resolved: (data) => `Got: ${JSON.stringify(data)}`, Rejected: (error) => `Failed: ${error.message}`,});match is exhaustive — TypeScript will complain if you miss a state, and the value in each branch is narrowed to that state’s data.
Interactive Example
Section titled “Interactive Example”A simple fetcher hitting a public API. Click Fetch to walk it through Idle → Pending → Resolved. The graph on the left highlights the current state in real time.
import { createPromiseMachine } from "matchina";
// Function to create a promise machine for fetching dataexport function createPromiseFetcherMachine() { return createPromiseMachine(async (url: string, options?: RequestInit) => { const response = await fetch(url, options); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return response.json(); });}When you need more
Section titled “When you need more”The basic shape covers most cases. For production data fetching you usually want cancellation, retries, and timeouts on top. The advanced fetcher shows one way to layer those without losing type safety:
It uses the same createPromiseMachine underneath plus lifecycle hooks to manage AbortControllers and a retry counter. Read the source to see the composition pattern — it’s not magic, just a few well-placed effect calls.
Next steps
Section titled “Next steps”- Lifecycle & Hooks — react to state transitions
- React Integration —
useMachineand rendering patterns - State Machines — when you need richer than four states