Failure Modes in React + TypeScript
On this page
High Impact Failure Sources
- Boundary typing errors: API, storage, URL params, third party callbacks.
- Unsafe casts and any spread across components.
- State models that allow invalid combinations.
- Stale closures from missing dependencies in hooks.
Symptom to Cause Mapping
- Random runtime crashes after deploy → unsafe cast or invalid boundary data.
- UI shows old values → stale closure or missing dependency array items.
- Errors hidden or unreachable → missing union variants or boolean soup.
- Data shape mismatch after backend change → UI reading DTO directly instead of mapping.
- Performance regression → any causes broad props, unstable context values, over wide state updates.
Fast Audit Checklist
- Search for explicit any, unknown as, and large type assertions.
- Verify all API boundaries validate and map DTO to ViewModel.
- Confirm async state uses discriminated unions with explicit status.
- Check useEffect and useCallback dependencies for completeness.
- Verify context providers memoize object values.
Boundary Validation Pattern
function isRecord(x: unknown): x is Record<string, unknown> {
return typeof x === "object" && x !== null;
}
function getString(r: Record<string, unknown>, k: string): string {
const v = r[k];
if (typeof v !== "string") throw new Error("invalid");
return v;
}
type UserVM = { id: string; name: string };
function parseUserVM(x: unknown): UserVM {
if (!isRecord(x)) throw new Error("invalid");
return { id: getString(x, "id"), name: getString(x, "name") };
}
State Model Upgrade Pattern
type LoadState =
| { status: "loading" }
| { status: "error"; message: string }
| { status: "ready"; data: UserVM[] };
Common Failure Modes
- Any spreading from one file into the entire component tree.
- DTO fields leaking into UI components, causing breakage on backend rename.
- Non null assertions hiding undefined paths and crashing later.
- Union gaps forcing unsafe casts and unreachable UI states.
- Effects that set state and re trigger themselves, creating loops.
Incident Triage Playbook
- Step 1: Reproduce with minimal state and log boundary inputs.
- Step 2: Identify first unsafe cast in the data path.
- Step 3: Add validation and mapping at the boundary.
- Step 4: Replace boolean soup with union status state.
- Step 5: Add tests for loading, error, empty, and ready paths.
Release Gate Checklist
- No any at boundaries.
- DTO mapping exists and is tested for required fields.
- Unions cover all states and rendering is switch based.
- Hooks have correct dependency arrays.
- Context values are stable and memoized where needed.