TypeScript
Beginner
1 min read
Branded Types and Opaque Types
Example
// Brand utility type
type Brand<T, B extends string> = T & { readonly __brand: B };
// Branded primitive types
type UserId = Brand<number, "UserId">;
type OrderId = Brand<number, "OrderId">;
type Email = Brand<string, "Email">;
type USD = Brand<number, "USD">;
type EUR = Brand<number, "EUR">;
// Factory functions that create branded values
function asUserId(n: number): UserId { return n as UserId; }
function asOrderId(n: number): OrderId { return n as OrderId; }
function parseEmail(raw: string): Email {
if (!/^[^@]+@[^@]+\.[^@]+$/.test(raw)) {
throw new Error(`Invalid email: ${raw}`);
}
return raw as Email;
}
// Functions that only accept the correct branded type
function fetchUser(id: UserId): Promise<string> {
return Promise.resolve(`User ${id}`);
}
const userId = asUserId(1);
const orderId = asOrderId(1);
fetchUser(userId); // OK
// fetchUser(orderId); // Error: OrderId is not assignable to UserId
// fetchUser(1); // Error: number is not assignable to UserId
// Currency brands prevent mixing
function addUSD(a: USD, b: USD): USD { return (a + b) as USD; }
const price: USD = 19.99 as USD;
const tax: USD = 1.60 as USD;
const total = addUSD(price, tax);
const eur: EUR = 18.00 as EUR;
// addUSD(price, eur); // Error: EUR is not assignable to USD
Related Resources
TypeScript Reference
Complete tag & property list
TypeScript How-To Guides
Step-by-step practical guides
TypeScript Exercises
Practice what you've learned
More in TypeScript