Branded Types for IDs
--
Prevent accidentally mixing different ID types with branded types. TypeScript catches bugs at compile time.
// Create a branded typetype Brand<K, T> = K & { __brand: T };
// Define specific ID typestype UserId = Brand<string, 'UserId'>;type PostId = Brand<string, 'PostId'>;type CommentId = Brand<string, 'CommentId'>;
// Helper to create branded valuesfunction userId(id: string): UserId { return id as UserId;}
function postId(id: string): PostId { return id as PostId;}
function commentId(id: string): CommentId { return id as CommentId;}
// Example usagefunction getUser(id: UserId) { return fetch(`/api/users/${id}`);}
function getPost(id: PostId) { return fetch(`/api/posts/${id}`);}
const uid = userId('user-123');const pid = postId('post-456');
getUser(uid); // ✅ WorksgetUser(pid); // ❌ Type error! Can't use PostId as UserId
// Prevents bugs like:// getUser(post.id) // Would be a runtime errorBonus: UUID validation
import { z } from 'zod';
const userIdSchema = z.string().uuid().transform(id => id as UserId);
// Validates AND brands in one stepconst validatedId = userIdSchema.parse('550e8400-e29b-41d4-a716-446655440000');When to use:
- APIs with multiple ID types
- Preventing ID mix-ups in database queries
- Type safety without runtime overhead