@prosopo/ts-brand
v2.1.14
Published
Brand your TypeScript types
Downloads
577
Readme
Brand your TypeScript types
See our tutorial for more info on what branding is and why you'd want to use it.
Nominal types example
type A = {
x: number
y: boolean
z: string
}
type B = {
x: number
y: boolean
z: string
}
Type A
and B
are equal in the eyes of TypeScript.
const fn = (a: A) => {
console.log('do something with A')
}
const obj: B = {
x: 1,
y: true,
z: 'hello',
}
fn(obj) // absolutely fine, even though fn accepts types of A and obj is of type B!
Let's brand A
type ABranded = Brand<A, 'A'> // {
// x: number;
// y: boolean;
// z: string;
// } & {
// [brandKey]: "A";
// }
const fn = (a: ABranded) => {
console.log('do something with A')
}
const obj: B = {
x: 1,
y: true,
z: 'hello',
}
fn(obj) // Now this doesn't work, cannot accept any type other than ABranded!
Now the function only accepts a set type.
Mapped type example
Using ABranded
from before, we can do conditional typing.
type IsA<T> = T extends ABranded ? true : false
type x = IsA<ABranded> // true
type y = IsA<B> // false
Obviously this is a simple example, but branding enables conditional typing. This would be impossible using regular types in TypeScript, because type B
is seen as equal to type A
. Read our blog post for a more detailed explanation.
Classes & Instances
You can brand instances of a class or the class itself (which will produce branded instances).
class Dog {
constructor(public name: string) {}
}
const DogBranded = brandClass(Dog, 'Dog') // adds the 'Dog' brand, making a new type
const dog = new DogBranded('Spot') // ok, of type DogBranded
Conditional typing can now be done using classes.
Or to brand an instance:
const dogBranded = brand(new Dog(), 'Dog') of type Dog & { [brandKey]: 'Dog' }
Unbranding
Simply do the inverse to get back to the original type.
const DogUnbranded = unbrandClass(DogBranded) // same as the Dog class
const dog = new DogUnbranded('Spot') // ok, of type Dog
Or to unbrand an instance:
const dogUnbranded = unbrand(dog) // of type Dog
Get brand
Given a unknown branded value
const b = getBrand(dog) // b is of type 'Dog'
No brand set:
const b = getBrand(someValue) // b is of type '' - i.e. no brand
Important note
Branding is type only, so only available at compile time! This means using things like getBrand()
will give you the brand as a type, not as a runtime variable!