Branding/opaque types to prevent unit mixups
Prevent unit/tag mixups by intersecting base types with phantom brand properties; construct via factory functions only.
Branding/opaque types to prevent unit mixups is a free TypeScript Academy lesson on CoddyKit — lesson 1 of 3. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the TypeScript Academy learning path, one of 3 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Intro
Goal: Separate look-alike values at the type level. A plain number cannot tell meters from seconds; a brand marker can.
- Zero runtime overhead
- Safer APIs and refactors
- Create via factories only
Brand primitive units
Brand markers keep units apart at compile time; wrong argument order fails type-checking.
type Meter = number & { readonly __brand: "meter" }
type Second = number & { readonly __brand: "second" }
function meter(n: number): Meter { return n as Meter }
function second(n: number): Second { return n as Second }
const d = meter(100)
const t = second(9)
function speed(dist: Meter, time: Second) { return (dist as number) / (time as number) }
// speed(t, d) // compile error: brands do not matchGeneric brand helper
Use a generic Brand helper across domains: typed IDs, tokens, cursors, etc.
type Brand<Tag extends string, T> = T & { readonly __brand: Tag }
type UserId = Brand<"UserId", string>
type OrderId = Brand<"OrderId", string>
function userId(x: string): UserId { return x as UserId }
function orderId(x: string): OrderId { return x as OrderId }
function findUser(id: UserId) { /* ... */ }
const u = userId("u_123")
const o = orderId("o_456")
// findUser(o) // error: OrderId not assignable to UserIdUnique symbol brand
unique symbol brand avoids name collisions and leaking into global namespaces.
declare const MeterSym: unique symbol
type Meter2 = number & { readonly [MeterSym]: "meter" }
function asMeter2(n: number): Meter2 { return n as Meter2 }
const m2 = asMeter2(5)
// const wrong: Meter2 = 5 // discourage raw assignment; prefer factoriesFactories & validation
Give the brand inside a factory: validate first, then brand, then consume. Avoid ad-hoc as at call sites.
type NonEmptyString = string & { readonly __brand: "NonEmpty" }
function nonEmpty(s: string): NonEmptyString | null {
return s.trim().length > 0 ? (s as NonEmptyString) : null
}
function makeSlug(s: NonEmptyString) {
return (s as string).toLowerCase().replace(/\s+/g, "-")
}
const ok = nonEmpty(" Hello ")
if (ok) { makeSlug(ok) } // safe: validated & branded firstTips & gotchas
Best practices:
- Keep brand names short and meaningful.
- Expose factories as the only way to obtain branded values.
- Do not leak brands in public API types unless necessary.
- Brands are type-level only: no runtime overhead.
Branding check
Quick check: Which pattern prevents unit/tag mixups?
Recap
Recap: Branded/opaque types separate look-alike values (meters vs seconds, UserId vs OrderId). Produce them via factories, use them across APIs, and eliminate accidental mixups.
Frequently asked questions
Is the “Branding/opaque types to prevent unit mixups” lesson free?
Yes — the full text of “Branding/opaque types to prevent unit mixups” is free to read here on the web, and the TypeScript Academy course includes 3 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the TypeScript Academy course, upgrade to CoddyKit PRO.
What will I learn in “Branding/opaque types to prevent unit mixups”?
Prevent unit/tag mixups by intersecting base types with phantom brand properties; construct via factory functions only. You practise TypeScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start TypeScript Academy?
No prior experience is required. TypeScript Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 3, so you can start here or from the beginning and move at your own pace.
How long does the “Branding/opaque types to prevent unit mixups” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this TypeScript Academy lesson?
Yes. Every TypeScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Branding/opaque types to prevent unit mixups
- Tagged IDs and domain modeling patterns
- Domain modeling — aggregates, invariants & services