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.