Last active
June 28, 2021 21:48
-
-
Save brettinternet/b32a63f057eb58f1a2de3765141097a7 to your computer and use it in GitHub Desktop.
Branded types with TypeScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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