타입 브랜딩(Type Branding)은 같은 구조의 타입(예: 둘 다 string인 UserId와 PostId)을 서로 다른 타입으로 취급하게 하려고, 실제로는 없는 표식 속성을 교집합으로 붙이는 패턴이다. 구조적 타이핑 위에서 명목적 타이핑(Nominal Typing)을 흉내 낸다.
type Brand<T, B> = T & { readonly __brand: B }
type UserId = Brand<string, 'UserId'>
type PostId = Brand<string, 'PostId'>
function getUser(id: UserId) {}
getUser('u_1' as UserId) // ✅
getUser('p_1' as PostId) // ❌ 다른 브랜드- 용도: ID 섞임 방지, 단위 구분(
Meter·Kilometer), 검증을 통과한 값 표시(Email,SanitizedHTML) - 검증 함수만 브랜드 타입을 반환하게 하면 "검증된 값만 이 함수에 들어온다"를 타입으로 강제할 수 있다. Zod의
.brand()도 같은 아이디어다 __brand는 예약어가 아니라 관례다. 이름은 무엇이든 되지만, 여러 브랜드가 같은 속성 이름을 쓰고 값으로 구분해야 헬퍼 하나로 관리하기 쉽다- 브랜드는 타입에만 있고 런타임에는 사라진다. 만들 때
as가 필요하므로 그 단언은 검증 함수 한 곳에만 둔다 - 같은 문제를 클래스로 푸는 방법이 값 객체이고, 원시값을 그대로 쓰는 냄새는 기본형 집착이다. 외부 값은 unknown으로 받아 검증 후 브랜드를 붙인다