Skip to content

Instantly share code, notes, and snippets.

@zgotsch
Created September 13, 2023 03:24
Show Gist options
  • Save zgotsch/e59d64723ce95cf5a8fd2d0a482b6242 to your computer and use it in GitHub Desktop.
Save zgotsch/e59d64723ce95cf5a8fd2d0a482b6242 to your computer and use it in GitHub Desktop.
Nominal Types
// Typescript 5.2.2
// https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBDAnmYcBCUCGA7AJgHgBUAadAPjgF45C4AyOAbwH1mAjLPALnQF96mrAO4BLGNmABnST0K8A3ACgkKOAEFsiDDlxV0nAgFdsAa2wQh2UsbMXsZJStQBVbBx340cUDGB5J6praeBTUaADaAETCYhLSkQC6SoqgkLBwAGbGAMYwIhDYcO54RKRoZAAUILIAlDzBBCTkTIpwcFDAMIZQhSBwmAE4iEq8iing0PBZ2Ln5hcW4AMKelXVwRJXVNDVUFA2lzYytbe2d3YVVO5QUfQP9miNj2QWSUxAQepEZ75H9Ac-YV6OZCoACi2DySAAkrpqCx2AYeJFwZDEDDIgplCC4CixGjcAAmPT7V5QETYADmpGRELx6LITxe8D61AWFW+EB2kkweUkGREUjgACUzj1CCD8E4IBkigZ8DZzJZqbjobhImQHIoAPRak5wAB6AH5GYD4Ig9GyOVyeSI+QKAvsFXZlbTVeqlDq9UaTa84AAvC0GZY01H0io1dnvGoe3Unb2KPrc3n8wUq-GKc1J20pgJpmGKANZu2p13phNwIs5nGlmEEjMVm3F3M1wkFhvJ+3V0OtrGqZx6VwLSUg6VwEAMz1teMA30wCB52GynTBhfq8NKGfwTB6OcLyOcmNew1AA
export type Brand<T, B> = T & {__brand: B} & {__witness: T};
type AnyBrand = Brand<unknown, unknown>;
type Unbrand<B extends AnyBrand> = B["__witness"];
export function brand<T, B>(x: T): Brand<T, B> {
return x as any;
}
export function brandC<B>(): <T>(x: T) => Brand<T, B> {
return (x) => x as any;
}
const foo = "foo" as const;
type EntityId = {__brand: "EntityId"};
type EntityId2 = Brand<string, "EntityId">
const x = brand(foo) satisfies ReturnType<typeof brand<unknown, "EntityId">>;
// ^?
const y = brand(foo) satisfies Brand<unknown, "EntityId">;
// ^?
const z = brandC<"EntityId">()(foo);
// ^?
x satisfies EntityId
y satisfies EntityId
z satisfies EntityId
x satisfies EntityId2
y satisfies EntityId2
z satisfies EntityId2
type U = Unbrand<typeof x>
// ^?
const toEntityId = brandC<"EntityId">();
const a = toEntityId(foo);
// ^?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment