Add nominal typing to string identifiers

TypeScript
// Branded types: separate ID kinds that are still plain strings at runtime.
declare const brand: unique symbol;

type Brand<T, B extends string> = T & { readonly [brand]: B };
type UserId = Brand<string, 'UserId'>;
type OrderId = Brand<string, 'OrderId'>;

function asUserId(value: string): UserId {
  if (!/^u_[a-z0-9]{6,}$/.test(value)) throw new TypeError(`bad user id: ${value}`);
  return value as UserId;
}

function asOrderId(value: string): OrderId {
  if (!/^o_[a-z0-9]{6,}$/.test(value)) throw new TypeError(`bad order id: ${value}`);
  return value as OrderId;
}

function loadOrder(orderId: OrderId): string {
  return `loaded ${orderId}`;
}

const orderId = asOrderId('o_abc123');
console.log(loadOrder(orderId));
// loadOrder(asUserId('u_abc123')); // type error: UserId is not OrderId