~/swaraj.dev
Back to all posts
April 10, 20261 min read

Branded Types: Safer IDs in React Native with TypeScript

Use TypeScript branded types to prevent accidental ID mix‑ups across entities, improving type safety in React Native apps.

typescriptreact-nativebest-practices

Insight

In many mobile apps, IDs are just strings or numbers, and it's easy to pass a userId where a postId is expected. TypeScript's structural typing treats both as the same primitive, so bugs slip through until runtime. Branded (or nominal) types let you create distinct compile‑time types for each ID without adding runtime overhead, catching mismatches during development.

Example

// Define a brand helper
type Brand<K, T> = K & { __brand: T };

// Create distinct ID types
type UserId = Brand<string, 'UserId'>;
type PostId = Brand<string, 'PostId'>;

// Helper to cast raw strings safely
const asUserId = (id: string): UserId => id as UserId;
const asPostId = (id: string): PostId => id as PostId;

// Usage in a component
function fetchPost(userId: UserId, postId: PostId) {
  // API call …
}

// TypeScript will error if you swap them
fetchPost(asUserId('u123'), asPostId('p456')); // ✅ correct
// fetchPost(asUserId('u123'), asUserId('u999')); // ❌ type error

Takeaway

Introduce branded ID types for every domain entity. They add zero runtime cost but give you compile‑time guarantees that you’re never feeding a UserId into a PostId parameter, dramatically reducing a class of subtle bugs in larger React Native codebases.