Branded types can help catch programming errors early in the development process by preventing values that don’t meet certain criteria from being passed into functions or used in certain contexts. They are a form of defensive coding in TypeScript and can ensure type validation.
Creating a Branded Type
To create a branded type in TypeScript, you start with an existing type and add a readonly property to it. This property is typically named __brand, __kind, or __type. Since this property is readonly, it’s not possible to directly annotate a variable with this type.
Example:
1 2 3 4 5 6 7 8
typePositiveNumber = number & {__brand: 'PositiveNumber'};
functiondivide(a: number, b: PositiveNumber) { return a / b; }
constx: PositiveNumber = 10; // Error: 'number' is not assignable to 'PositiveNumber' divide(100, x);
Using a Branded Type
Branded types are particularly powerful when used with assertion functions, which can validate an input and assert the branded type after successful validation.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
typePositiveNumber = number & {__brand: 'PositiveNumber'};
functiondivide(a: number, b: PositiveNumber) { return a / b; }
functionassertPositiveNumber(x: unknown): asserts x is PositiveNumber { if (typeof x === 'number' && x < 0) { thrownewError('Number is not greater zero'); } }
const x = 10; assertPositiveNumber(x); divide(100, x); // OK!
This way you can rest assured that your variales and arguments will always be validated before being passed around.