Skip to main content
Daniel Cohen·

Killed every `any` in our payments module with branded UserId vs OrderId types

Adds comprehensive type safety to untyped or loosely-typed code including branded types, phantom types, and utility types.

Type Safety Enhancement Engine

You are a type-system expert making code maximally type-safe. Transform the following code with comprehensive typing. ## Code to Type ```{{programming_language}} {{untyped_code}} ``` ## Type System Requirements - Language: {{programming_language}} (TypeScript, Python with typing, Rust, Go, etc.) - Strictness: {{strictness}} (maximum, balanced, gradual) - Type checker: {{type_checker}} (tsc, mypy, rustc, go vet) ## Enhancements to Apply 1. **Complete Type Annotations** - Every parameter, return value, variable typed 2. **Branded/Opaque Types** - For ID fields and domain primitives (e.g., UserId vs OrderId) 3. **Discriminated Unions** - For states, events, and API responses 4. **Generic Constraints** - Where functions operate on related types 5. **Phantom Types** - For compile-state verification where applicable 6. **Validation Types** - Runtime-validated types at system boundaries (zod, io-ts, pydantic) 7. **Mapped/Conditional Types** - TypeScript utility types for derived types 8. ** Exhaustive Switch/Pmatch** - Compile-time exhaustiveness checking 9. **Nominal Typing** - Distinguish semantically different primitives 10. **Type-Level Tests** - Tests that verify type behavior (tsd, typecheck tests) ## Output 1. Fully typed code preserving all runtime behavior 2. Helper types and utility types used 3. Explanation of key type decisions 4. Before/after type safety comparison 5. Any runtime validation schemas for boundaries Eliminate ALL `any`, `unknown` (unchecked), and `Object` types. Every type should communicate intent.

Ergebnisse

Made the payments helpers in this TypeScript module fully type-safe. Every `any` is gone; IDs can no longer be swapped. ```typescript // Branded primitives — a UserId can never be passed where an OrderId is expected type Brand<T, B> = T & { readonly __brand: B }; export type UserId = Brand<string, "UserId">; export type OrderId = Brand<string, "OrderId">; export const UserId = (s: string): UserId => s as UserId; // Discriminated union for payment state — exhaustively checked type Payment = | { status: "pending"; intentId: string } | { status: "succeeded"; receiptUrl: string } | { status: "failed"; reason: string }; function render(p: Payment): string { switch (p.status) { case "pending": return "Processing…"; case "succeeded": return p.receiptUrl; case "failed": return p.reason; default: return assertNever(p); // compile error if a case is added } } // Runtime validation at the HTTP boundary const ChargeInput = z.object({ userId: z.string().uuid(), amountCents: z.number().int().positive() }); ``` **Key decisions:** branded `UserId`/`OrderId` catch argument-order mistakes at compile time; the discriminated union plus `assertNever` makes adding a payment state a type error until handled; zod guards untrusted input where types alone can't. Result: zero `any`, full inference downstream.

Modell: Claude Sonnet 4

39 Likes8 SavesScore: 27

1 Kommentar

Priya Nair·

Didn't expect the graceful-shutdown handling, that's the detail that matters in prod.