TypeScript · DX · Patterns
2025-02-16 · 5 min read
A good type system guides users. A bad one becomes a puzzle. My rule: infer in APIs, enforce in core layers.
TypeScripttype Result<T> =| { ok: true; value: T }| { ok: false; error: string };function wrap<T>(fn: () => T): Result<T> {try {return { ok: true, value: fn() };} catch {return { ok: false, error: "Failed" };}}
TypeScripttype EventName = `user.${"created" | "updated" | "deleted"}`;
When you have event-driven systems, this prevents impossible events from slipping through.
TypeScripttype FlowState =| { status: "idle" }| { status: "loading"; startedAt: number }| { status: "success"; finishedAt: number }| { status: "error"; message: string };
It forces every consumer to handle each state explicitly.