Generate Branded Types from JSON IDs in TypeScript
Use json to typescript with branded types so UserId and OrderId never get accidentally swapped, even though both are strings at runtime.
Detailed Explanation
Nominal Typing for ID Fields
JSON IDs are usually strings, but a UserId and an OrderId should never be interchangeable. Branded types add a phantom marker to the type without touching the runtime value.
Example JSON
{
"user_id": "usr_01H8X9",
"order_id": "ord_42",
"product_id": "prd_AB12",
"quantity": 3
}
Generated TypeScript
type Brand<T, B> = T & { readonly __brand: B };
type UserId = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;
type ProductId = Brand<string, "ProductId">;
interface OrderLine {
user_id: UserId;
order_id: OrderId;
product_id: ProductId;
quantity: number;
}
Why a Phantom Brand?
The intersection with { __brand: "UserId" } exists only at compile time. At runtime, a UserId is just a string, so JSON serialization, comparison, and storage all work unchanged. But the compiler refuses to assign a string (or an OrderId) to a UserId parameter:
function loadUser(id: UserId): Promise<User> { /* ... */ }
const o: OrderId = parseOrderId(req.body.order_id);
loadUser(o); // Error: OrderId not assignable to UserId
loadUser(req.body.user_id); // Error: string not assignable to UserId
Constructing Branded Values
You need a small parser per brand:
function asUserId(s: string): UserId {
if (!s.startsWith("usr_")) throw new Error("Invalid UserId");
return s as UserId;
}
This becomes the only legitimate way to mint a UserId, so you can audit ID provenance with a single grep.
When to Apply
Apply brands to every ID field that flows across module boundaries: API responses, database rows, function parameters. Skip them on purely local strings (component state, formatting). The result is a type system that catches the entire class of "passed user.id where order.id was expected" bugs at compile time.
Use Case
Stopping a recurring class of production bugs where developers passed an organization ID to a function expecting a user ID, both being strings at runtime.
Try It — JSON to TypeScript
Related Topics
Type ISO Date Strings vs Plain Strings in JSON-to-TypeScript
TypeScript Patterns
Generate Literal Status Unions from JSON for State Machines
TypeScript Patterns
JSON to TypeScript Discriminated Union — Result/Error Pattern
Real-World API Schemas
Convert Stripe Charge JSON to TypeScript Interfaces
Real-World API Schemas
Apply DeepReadonly to JSON-Generated TypeScript Types
TypeScript Patterns