Branded Types for Nominal Identity
Attach a phantom brand to primitive types so structurally identical identifiers such as UserId and OrderId cannot be mixed up.
Code
declare const brand: unique symbol;
export type Brand<T, B extends string> = T & { readonly [brand]: B };
export type UserId = Brand<string, "UserId">;
export type OrderId = Brand<string, "OrderId">;
export function asUserId(value: string): UserId {
if (!/^usr_[a-z0-9]+$/.test(value)) throw new Error("invalid user id");
return value as UserId;
}
export function loadUser(id: UserId): void {
console.log("loading user", id);
}
const orderId = "ord_1" as OrderId;
// loadUser(orderId); // compile error: OrderId is not UserIdReport a problem with this exampleOpens a pre-filled issue on GitHub.