CodeBlanks Logo Icon CodeBlanks

Summary - Branded types

Write unmixable UserId and OrderId with branded types.

Summary - Branded types

Branded types add nominal safety to TypeScript's structural type system. The marker field added via intersection makes types based on the same base type structurally distinct. Using declare with a unique symbol reduces runtime cost to zero. Validation helpers ensure the brand is only created with valid values.

type Brand<T, B extends string> = T & { readonly __brand: B };

type UserId = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;

function makeUserId(s: string): UserId {
  return s as UserId;
}

const uid = makeUserId("u1");
const oid: OrderId = uid;  // error: UserId is not assignable to OrderId

Practice Write UserId and OrderId branded types

Define the Brand<T, B> helper type with intersection. Create UserId and OrderId types with separate brands. Write makeUserId(s: string): UserId and makeOrderId(s: string): OrderId helper functions (both return with as). Create a uid value via makeUserId("u1") and an oid value via makeOrderId("o1"). Print both with console.log. Then print console.log("done").

Starter code

index.ts
// Brand<T, B> yardımcı türünü intersection ile tanımla

// UserId ve OrderId türlerini ayrı markalarla oluştur

// makeUserId ve makeOrderId yardımcı fonksiyonlarını yaz

// uid ve oid değerlerini oluştur ve yazdır, sonra "done" yazdır

Sample solution

index.ts
type Brand<T, B extends string> = T & { readonly __brand: B };

type UserId = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;

function makeUserId(s: string): UserId {
  return s as UserId;
}

function makeOrderId(s: string): OrderId {
  return s as OrderId;
}

const uid = makeUserId("u1");
const oid = makeOrderId("o1");

console.log(uid);
console.log(oid);
console.log("done");

Expected output

u1
o1
done

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What is the core benefit of the brand pattern?

  • Provide automatic code completion
  • Improve runtime performance
  • Make types based on the same base type structurally distinct Correct answer
  • Write shorter code

Explanation: The brand pattern provides nominal-like safety in a structural type system; it makes types based on the same base type (like UserId and OrderId) structurally distinct so they cannot be mixed up.

2 Separate UserId and OrderId with brands

Question
type Brand<T, B extends string> = T & { readonly __brand: B };

type UserId = Brand<string, "UserId">;
// OrderId, UserId'den farklı olmalı:
type OrderId = Brand<string, ____>;

const uid = "u1" as UserId;
const oid: OrderId = uid;  // hata: farklı markalar
Answer
type Brand<T, B extends string> = T & { readonly __brand: B };

type UserId = Brand<string, "UserId">;
// OrderId, UserId'den farklı olmalı:
type OrderId = Brand<string, "OrderId">;

const uid = "u1" as UserId;
const oid: OrderId = uid;  // hata: farklı markalar

Explanation: For OrderId to differ from UserId, the brand string must be different; using "UserId" would make OrderId identical to UserId and they would be assignable.

3 Branded types summary matching

Term Meaning
Yapısal tip sistemi same shape = assignable
Brand pattern distinct types from the same base
declare const __brand zero runtime code
Validation yardımcısı brand only with valid values

All lessons in Advanced