0Pricing
TypeScript Academy · Lesson

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 match

Generic 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 UserId

Unique 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 factories

Factories & 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 first

Tips & 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

  1. Branding/opaque types to prevent unit mixups
  2. Tagged IDs and domain modeling patterns
  3. Domain modeling — aggregates, invariants & services
← Back to TypeScript Academy