Last active
April 6, 2021 10:10
-
-
Save castarco/f720013b13f2572bf41eaf41296bdbb5 to your computer and use it in GitHub Desktop.
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
// We use symbols to eliminate any chance for problems with serialization | |
const __BaseType: unique symbol = new Symbol('__BaseType') | |
const __Brand: unique symbol = new Symbol('__Brand') | |
// We mark the "brand/flavor" fields as readonly to avoid anyone doing weird stuff with them | |
// We add a "__BaseType" field to make possible "complex" type manipulations | |
// We accept "symbol" tags as a mechanism to avoid "types forgery" to bypass the type checker, | |
// although I foresee that most of the times it won't be used. | |
export type Branded<BaseType, Tag extends string | symbol> = BaseType & { | |
readonly [__BaseType]: BaseType | |
readonly [__Brand]: Tag | |
} | |
export type Flavored<BaseType, Tag extends string | symbol> = BaseType & { | |
readonly [__BaseType]?: BaseType | |
readonly [__Brand]?: Tag | |
} | |
export type OurBrand = Branded<number, 'AnAnswer'> | |
export type OurFlavor = Flavored<number, 'AnAnswer'> | |
const primitive = 23 // ok, of course | |
const ourFirstBrandedValue: OurBrand = 42 as OurBrand // ok, of course | |
const ourSecondBrandedValue: OurBrand = 42 // error, it does not accept "unbranded" values | |
const ourThirdBrandedValue: OurBrand = 42 as OurFlavor // error, it does not accept flavored values | |
const ourFirstFlavoredValue: OurFlavor = 42 as OurFlavor // ok, of course | |
const ourSecondFlavoredValue: OurFlavor = 42 as OurBrand // luckily for us, ok too | |
const ourThirdFlavoredValue: OurFlavor = 42 // ok too, then, why are flavored types good for if it accepts "everything"? | |
export type TheirBrand = Branded<number, 'AQuestion'> | |
export type TheirFlavor = Flavored<number, 'AQuestion'> | |
// This is where flavored types are useful | |
const ourFourthFlavoredValue: OurFlavor = 42 as TheirBrand // error, so, flavored types are useful for something | |
const ourFifthFlavoredValue: OurFlavor = 42 as TheirFlavor // error as well |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment