Branded Types — TypeScript nominal typing ที่ไม่มีใน spec
string กับ string ที่เป็น UserId หรือ Email — TypeScript มองเหมือนกัน Branded Type ทำให้ต่าง เพิ่มความปลอดภัยโดยไม่มี runtime cost
TypeScript ใช้ structural typing — UserId และ ProductId ที่เป็น string สลับกันได้โดยไม่มี error:
type UserId = string;
type ProductId = string;
function getUser(id: UserId) { ... }
const productId: ProductId = 'prod-123';
getUser(productId); // ✅ TypeScript ยอม แต่นี่คือ bug!
Branded Type เพิ่ม phantom property เพื่อให้ type ต่างกัน:
type UserId = string & { readonly _brand: 'UserId' };
type ProductId = string & { readonly _brand: 'ProductId' };
function createUserId(id: string): UserId {
return id as UserId; // cast ทำครั้งเดียวที่ boundary
}
const userId = createUserId('user-456');
const productId = 'prod-123' as ProductId;
getUser(userId); // ✅
getUser(productId); // ❌ Error: _brand ไม่ตรง
ไม่มี runtime cost — _brand ไม่มีอยู่จริงในค่า เป็นแค่ type-level annotation ที่ TypeScript ใช้ตรวจสอบ