Skip to content

Introduction

expect-status replaces your per-status if/else boilerplate with a single, type-safe call. Zero runtime dependencies.

const res = await api.acceptInvite({ body: { token } })
if (res.status === 200 || res.status === 201) {
return res.body as Membership // unsafe cast
}
if (res.status === 409) {
return redirect(`/org/${(res.body as any).orgId}`) // as any
}
if (res.status === 422) {
throw new Error((res.body as any).message) // as any
}
// 401? 403? 429? 500? Hopefully we didn't miss one...
throw new Error('Something went wrong')
CapabilityHow
Type narrowingReturn type is the body of the matched branch — not unknown, not the full union
Flat dispatch{ 409: fn, 422: "msg" } — functions are handlers, strings throw with that message
Ranges & groups'4xx', '5xx', 'success', 'error', custom groups like 'auth'
Negation'!4xx' — anything except client errors
Returning handlersHandlers can return values, widening the return type
AdapterNormalize Axios, custom envelopes, or any non-standard shape
Instance defaultscreateExpectStatus with shared messages, hooks, and error class
ObservabilityonError / onSuccess hooks for Sentry, logging, metrics
Recover & transformCatch-all error fallback and success body reshaping
SafeResultthrows: false returns { ok, data, error } instead of throwing
Exhaustive checkingexhaustive: true — TypeScript flags uncovered error statuses
Message bubblingUnhandled errors extract body.message, RFC 7807 detail, and more

Quick Start — install, understand the response shape, and start coding