Skip to content

Instantly share code, notes, and snippets.

@brettinternet
Last active June 28, 2021 21:48
Show Gist options
  • Save brettinternet/b32a63f057eb58f1a2de3765141097a7 to your computer and use it in GitHub Desktop.
Save brettinternet/b32a63f057eb58f1a2de3765141097a7 to your computer and use it in GitHub Desktop.
Branded types with TypeScript
/**
* @source https://github.com/mike-works/typescript-fundamentals/blob/4e5782e00ed942ffe8770a694122190b6ed69b95/notes/6-guards-and-extreme-types.ts
* Helps guard against accidentally matching a type that might otherwise be easy to mismatch
*/
// Brand A
interface BrandedA {
__this_is_branded_with_a: "a"; // some unique primitive brand
}
function brandA(value: string): BrandedA {
return (value as unknown) as BrandedA;
}
function unbrandA(value: BrandedA): string {
return (value as unknown) as string;
}
// Brand B
interface BrandedB {
__this_is_branded_with_b: "b";
}
function brandB(value: { abc: string }): BrandedB {
return (value as unknown) as BrandedB;
}
function unbrandB(value: BrandedB): { abc: string } {
return (value as unknown) as { abc: string };
}
let secretA = brandA("This is a secret value");
let secretB = brandB({ abc: "This is a different secret value" });
secretA != secretB; // ✅ No chance of getting these mixed up
unbrandB(secretA);
unbrandA(secretB);
// back to our original values
let revealedA = unbrandA(secretA);
let revealedB = unbrandB(secretB);
// 💡 PROTIP - always brand/unbrand casting in exactly one place.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment