capypad
0 day streak
typescript / expert
Snippet

Nominal Typing via Branded Types

TypeScript uses structural typing, but sometimes we need nominal typing to prevent accidental mixing of logically different primitives (like different currencies or IDs). Branding 'tags' a type with a unique property that doesn't exist at runtime but enforces strict separation at compile time.

snippet.ts
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
type Brand<K, T> = K & { __brand: T };
 
type USD = Brand<number, "USD">;
type EUR = Brand<number, "EUR">;
 
const usd = 10 as USD;
const eur = 10 as EUR;
 
function addUSD(a: USD, b: USD): USD {
return (a + b) as USD;
}
 
// Error: Argument of type 'EUR' is not assignable to 'USD'
// addUSD(usd, eur);
Breakdown
1
type Brand<K, T> = K & { __brand: T };
Creates an intersection type that combines the base type with a phantom property used only for type checking.
2
const usd = 10 as USD;
Type assertion is required to 'brand' the primitive value, as the __brand property doesn't exist on a raw number.