typescript / expert
Snippet
Branded Email Types via Smart Constructors
TypeScript's structural type system normally treats every `string` as interchangeable, so validated values silently mix with raw input. A branded type tags a primitive with a phantom `unique symbol` property, making it nominally distinct at the type level without runtime cost. The only way to produce an `Email` is to pass through `parseEmail`, the smart constructor that enforces the invariant. Downstream functions can then trust the brand and skip defensive re-validation.
snippet.ts
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
declare const __brand: unique symbol;type Brand<T, B extends string> = T & { readonly [__brand]: B };type Email = Brand<string, "Email">;function parseEmail(raw: string): Email | null {return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(raw) ? (raw as Email) : null;}function sendMail(to: Email): void {console.log(`mailing ${to}`);}if (candidate) sendMail(candidate);
Breakdown
1
declare const __brand: unique symbol;
Unique symbol key — guaranteed not to collide with any property name.
2
type Brand<T, B extends string> = T & { readonly [__brand]: B };
Intersects T with a phantom property carrying the brand string.
3
return /.../.test(raw) ? (raw as Email) : null;
Smart constructor: the assertion is the single trusted entry point.
4
if (candidate) sendMail(candidate);
Caller must narrow before passing — raw strings would be a type error.