Branded Types
In this guide, we will explore the concept of branded types in TypeScript and learn how to create and work with them using the Brand module. Branded types are TypeScript types with an added type tag that helps prevent accidental usage of a value in the wrong context. They allow us to create distinct types based on an existing underlying type, enabling type safety and better code organization.
TypeScript’s type system is structurally typed, meaning that two types are considered compatible if their members are compatible. This can lead to situations where values of the same underlying type are used interchangeably, even when they represent different concepts or have different meanings.
Consider the following types:
1type type UserId = number
UserId = number2
3type type ProductId = number
ProductId = number
Here, UserId
and ProductId
are structurally identical as they are both based on number
.
TypeScript will treat these as interchangeable, potentially causing bugs if they are mixed up in your application.
For example:
1type type UserId = number
UserId = number2
3type type ProductId = number
ProductId = number4
5const const getUserById: (id: UserId) => void
getUserById = ((parameter) id: number
id: type UserId = number
UserId) => {6 // Logic to retrieve user7}8
9const const getProductById: (id: ProductId) => void
getProductById = ((parameter) id: number
id: type ProductId = number
ProductId) => {10 // Logic to retrieve product11}12
13const const id: number
id: type UserId = number
UserId = 114
15const getProductById: (id: ProductId) => void
getProductById(const id: number
id) // No type error, but this is incorrect usage
In the example above, passing a UserId
to getProductById
should ideally throw a type error, but it doesn’t due to structural compatibility.
Branded types allow you to create distinct types from the same underlying type by adding a unique type tag, enforcing proper usage at compile-time.
Branding is accomplished by adding a symbolic identifier that distinguishes one type from another at the type level. This method ensures that types remain distinct without altering their runtime characteristics.
Let’s start by introducing the BrandTypeId
symbol:
1const const BrandTypeId: typeof BrandTypeId
BrandTypeId: unique symbol = var Symbol: SymbolConstructor
Symbol.(method) SymbolConstructor.for(key: string): symbol
Returns a Symbol object from the global symbol registry matching the given key if found.
Otherwise, returns a new symbol with this key.
for("effect/Brand")2
3type type ProductId = number & {
readonly [BrandTypeId]: {
readonly ProductId: "ProductId";
};
}
ProductId = number & {4 readonly [const BrandTypeId: typeof BrandTypeId
BrandTypeId]: {5 readonly (property) ProductId: "ProductId"
ProductId: "ProductId" // unique identifier for ProductId6 }7}
This approach assigns a unique identifier as a brand to the number
type, effectively differentiating ProductId
from other numerical types.
The use of a symbol ensures that the branding field does not conflict with any existing properties of the number
type.
Attempting to use a UserId
in place of a ProductId
now results in an error:
1const const BrandTypeId: typeof BrandTypeId
BrandTypeId: unique symbol = var Symbol: SymbolConstructor
Symbol.(method) SymbolConstructor.for(key: string): symbol
Returns a Symbol object from the global symbol registry matching the given key if found.
Otherwise, returns a new symbol with this key.
for("effect/Brand")2
3type type ProductId = number & {
readonly [BrandTypeId]: {
readonly ProductId: "ProductId";
};
}
ProductId = number & {4 readonly [const BrandTypeId: typeof BrandTypeId
BrandTypeId]: {5 readonly (property) ProductId: "ProductId"
ProductId: "ProductId"6 }7}8
9const const getProductById: (id: ProductId) => void
getProductById = ((parameter) id: ProductId
id: type ProductId = number & {
readonly [BrandTypeId]: {
readonly ProductId: "ProductId";
};
}
ProductId) => {10 // Logic to retrieve product11}12
13type type UserId = number
UserId = number14
15const const id: number
id: type UserId = number
UserId = 116
17// @ts-expect-error18const getProductById: (id: ProductId) => void
getProductById(const id: number
id)19/*20Argument of type 'number' is not assignable to parameter of type 'ProductId'.21 Type 'number' is not assignable to type '{ readonly [BrandTypeId]: { readonly ProductId: "ProductId"; }; }'.ts(2345)22*/
The error message clearly states that a number
cannot be used in place of a ProductId
.
TypeScript won’t let us pass an instance of number
to the function accepting ProductId
because it’s missing the brand field.
What if UserId
also had its own brand?
1const const BrandTypeId: typeof BrandTypeId
BrandTypeId: unique symbol = var Symbol: SymbolConstructor
Symbol.(method) SymbolConstructor.for(key: string): symbol
Returns a Symbol object from the global symbol registry matching the given key if found.
Otherwise, returns a new symbol with this key.
for("effect/Brand")2
3type type ProductId = number & {
readonly [BrandTypeId]: {
readonly ProductId: "ProductId";
};
}
ProductId = number & {4 readonly [const BrandTypeId: typeof BrandTypeId
BrandTypeId]: {5 readonly (property) ProductId: "ProductId"
ProductId: "ProductId" // unique identifier for ProductId6 }7}8
9const const getProductById: (id: ProductId) => void
getProductById = ((parameter) id: ProductId
id: type ProductId = number & {
readonly [BrandTypeId]: {
readonly ProductId: "ProductId";
};
}
ProductId) => {10 // Logic to retrieve product11}12
13type type UserId = number & {
readonly [BrandTypeId]: {
readonly UserId: "UserId";
};
}
UserId = number & {14 readonly [const BrandTypeId: typeof BrandTypeId
BrandTypeId]: {15 readonly (property) UserId: "UserId"
UserId: "UserId" // unique identifier for UserId16 }17}18
19declare const const id: UserId
id: type UserId = number & {
readonly [BrandTypeId]: {
readonly UserId: "UserId";
};
}
UserId20
21// @ts-expect-error22const getProductById: (id: ProductId) => void
getProductById(const id: UserId
id)23/*24Argument of type 'UserId' is not assignable to parameter of type 'ProductId'.25 Type 'UserId' is not assignable to type '{ readonly [BrandTypeId]: { readonly ProductId: "ProductId"; }; }'.26 Types of property '[BrandTypeId]' are incompatible.27 Property 'ProductId' is missing in type '{ readonly UserId: "UserId"; }' but required in type '{ readonly ProductId: "ProductId"; }'.ts(2345)28*/
The error is saying that though both types utilize a branding strategy, the distinct values associated with their branding fields ("ProductId"
and "UserId"
) prevent them from being interchangeable.
To enhance the versatility and reusability of branded types, they can be generalized using a standardized approach:
1const const BrandTypeId: typeof BrandTypeId
BrandTypeId: unique symbol = var Symbol: SymbolConstructor
Symbol.(method) SymbolConstructor.for(key: string): symbol
Returns a Symbol object from the global symbol registry matching the given key if found.
Otherwise, returns a new symbol with this key.
for("effect/Brand")2
3// Create a generic Brand interface using a unique identifier4interface interface Brand<in out ID extends string | symbol>
Brand<in out (type parameter) ID in Brand<in out ID extends string | symbol>
ID extends string | symbol> {5 readonly [const BrandTypeId: typeof BrandTypeId
BrandTypeId]: {6 readonly [(type parameter) id
id in (type parameter) ID in Brand<in out ID extends string | symbol>
ID]: (type parameter) ID in Brand<in out ID extends string | symbol>
ID7 }8}9
10// Define a ProductId type branded with a unique identifier11type type ProductId = number & Brand<"ProductId">
ProductId = number & interface Brand<in out ID extends string | symbol>
Brand<"ProductId">12
13// Define a UserId type branded similarly14type type UserId = number & Brand<"UserId">
UserId = number & interface Brand<in out ID extends string | symbol>
Brand<"UserId">
This design allows any type to be branded using a unique identifier, either a string or symbol.
Here’s how you can utilize the Brand
interface, which is readily available from the Brand module, eliminating the need to craft your own implementation:
1import { Brand } from "effect"2
3// Define a ProductId type branded with a unique identifier4type ProductId = number & Brand.Brand<"ProductId">5
6// Define a UserId type branded similarly7type UserId = number & Brand.Brand<"UserId">
However, creating instances of these types directly leads to an error because the type system expects the brand structure:
1const const BrandTypeId: typeof BrandTypeId
BrandTypeId: unique symbol = var Symbol: SymbolConstructor
Symbol.(method) SymbolConstructor.for(key: string): symbol
Returns a Symbol object from the global symbol registry matching the given key if found.
Otherwise, returns a new symbol with this key.
for("effect/Brand")2
3interface interface Brand<in out K extends string | symbol>
Brand<in out (type parameter) K in Brand<in out K extends string | symbol>
K extends string | symbol> {4 readonly [const BrandTypeId: typeof BrandTypeId
BrandTypeId]: {5 readonly [(type parameter) k
k in (type parameter) K in Brand<in out K extends string | symbol>
K]: (type parameter) K in Brand<in out K extends string | symbol>
K6 }7}8
9type type ProductId = number & Brand<"ProductId">
ProductId = number & interface Brand<in out K extends string | symbol>
Brand<"ProductId">10
11// @ts-expect-error12const const id: ProductId
id: type ProductId = number & Brand<"ProductId">
ProductId = 113/*14Type 'number' is not assignable to type 'ProductId'.15 Type 'number' is not assignable to type 'Brand<"ProductId">'.ts(2322)16*/
We need a way to create a value of type ProductId
without directly assigning a number to it. This is where the Brand module comes in.
The Brand module offers two core functions for constructing branded types: nominal
and refined
.
The nominal
function is designed for defining branded types that do not require runtime validations.
It simply adds a type tag to the underlying type, allowing us to distinguish between values of the same type but with different meanings.
Nominal branded types are useful when we only want to create distinct types for clarity and code organization purposes.
1import { import Brand
Brand } from "effect"2
3type type UserId = number & Brand.Brand<"UserId">
UserId = number & import Brand
Brand.interface Brand<in out K extends string | symbol>
namespace Brand
A generic interface that defines a branded type.
Brand<"UserId">4
5// Constructor for UserId6const const UserId: Brand.Brand.Constructor<UserId>
UserId = import Brand
Brand.const nominal: <UserId>() => Brand.Brand<in out K extends string | symbol>.Constructor<UserId>
This function returns a `Brand.Constructor` that **does not apply any runtime checks**, it just returns the provided value.
It can be used to create nominal types that allow distinguishing between two values of the same type but with different meanings.
If you also want to perform some validation, see
{@link
refined
}
.
nominal<type UserId = number & Brand.Brand<"UserId">
UserId>()7
8const const getUserById: (id: UserId) => void
getUserById = ((parameter) id: UserId
id: type UserId = number & Brand.Brand<"UserId">
UserId) => {9 // Logic to retrieve user10}11
12type type ProductId = number & Brand.Brand<"ProductId">
ProductId = number & import Brand
Brand.interface Brand<in out K extends string | symbol>
namespace Brand
A generic interface that defines a branded type.
Brand<"ProductId">13
14// Constructor for ProductId15const const ProductId: Brand.Brand.Constructor<ProductId>
ProductId = import Brand
Brand.const nominal: <ProductId>() => Brand.Brand<in out K extends string | symbol>.Constructor<ProductId>
This function returns a `Brand.Constructor` that **does not apply any runtime checks**, it just returns the provided value.
It can be used to create nominal types that allow distinguishing between two values of the same type but with different meanings.
If you also want to perform some validation, see
{@link
refined
}
.
nominal<type ProductId = number & Brand.Brand<"ProductId">
ProductId>()16
17const const getProductById: (id: ProductId) => void
getProductById = ((parameter) id: ProductId
id: type ProductId = number & Brand.Brand<"ProductId">
ProductId) => {18 // Logic to retrieve product19}
Attempting to assign a non-ProductId
value will result in a compile-time error:
1import { import Brand
Brand } from "effect"2
3type type UserId = number & Brand.Brand<"UserId">
UserId = number & import Brand
Brand.interface Brand<in out K extends string | symbol>
namespace Brand
A generic interface that defines a branded type.
Brand<"UserId">4
5const const UserId: Brand.Brand.Constructor<UserId>
UserId = import Brand
Brand.const nominal: <UserId>() => Brand.Brand<in out K extends string | symbol>.Constructor<UserId>
This function returns a `Brand.Constructor` that **does not apply any runtime checks**, it just returns the provided value.
It can be used to create nominal types that allow distinguishing between two values of the same type but with different meanings.
If you also want to perform some validation, see
{@link
refined
}
.
nominal<type UserId = number & Brand.Brand<"UserId">
UserId>()6
7const const getUserById: (id: UserId) => void
getUserById = ((parameter) id: UserId
id: type UserId = number & Brand.Brand<"UserId">
UserId) => {8 // Logic to retrieve user9}10
11type type ProductId = number & Brand.Brand<"ProductId">
ProductId = number & import Brand
Brand.interface Brand<in out K extends string | symbol>
namespace Brand
A generic interface that defines a branded type.
Brand<"ProductId">12
13const const ProductId: Brand.Brand.Constructor<ProductId>
ProductId = import Brand
Brand.const nominal: <ProductId>() => Brand.Brand<in out K extends string | symbol>.Constructor<ProductId>
This function returns a `Brand.Constructor` that **does not apply any runtime checks**, it just returns the provided value.
It can be used to create nominal types that allow distinguishing between two values of the same type but with different meanings.
If you also want to perform some validation, see
{@link
refined
}
.
nominal<type ProductId = number & Brand.Brand<"ProductId">
ProductId>()14
15const const getProductById: (id: ProductId) => void
getProductById = ((parameter) id: ProductId
id: type ProductId = number & Brand.Brand<"ProductId">
ProductId) => {16 // Logic to retrieve product17}18
19// Correct usage20const getProductById: (id: ProductId) => void
getProductById(const ProductId: Brand.Brand<in out K extends string | symbol>.Constructor
(args: number) => ProductId
Constructs a branded type from a value of type `A`, throwing an error if
the provided `A` is not valid.
ProductId(1))21
22// Incorrect, will result in an error23// @ts-expect-error24const getProductById: (id: ProductId) => void
getProductById(1)25/*26Argument of type 'number' is not assignable to parameter of type 'ProductId'.27 Type 'number' is not assignable to type 'Brand<"ProductId">'.ts(2345)28*/29
30// Also incorrect, will result in an error31// @ts-expect-error32const getProductById: (id: ProductId) => void
getProductById(const UserId: Brand.Brand<in out K extends string | symbol>.Constructor
(args: number) => UserId
Constructs a branded type from a value of type `A`, throwing an error if
the provided `A` is not valid.
UserId(1))33/*34Argument of type 'UserId' is not assignable to parameter of type 'ProductId'.35 Type 'UserId' is not assignable to type 'Brand<"ProductId">'.36 Types of property '[BrandTypeId]' are incompatible.37 Property 'ProductId' is missing in type '{ readonly UserId: "UserId"; }' but required in type '{ readonly ProductId: "ProductId"; }'.ts(2345)38*/
The refined
function enables the creation of branded types that include data validation. It requires a refinement predicate to check the validity of input data against specific criteria.
When the input data does not meet the criteria, the function uses Brand.error
to generate a BrandErrors
data type. This provides detailed information about why the validation failed.
1import { import Brand
Brand } from "effect"2
3// Define a branded type 'Int' to represent integer values4type type Int = number & Brand.Brand<"Int">
Int = number & import Brand
Brand.interface Brand<in out K extends string | symbol>
namespace Brand
A generic interface that defines a branded type.
Brand<"Int">5
6// Define the constructor using 'refined' to enforce integer values7const const Int: Brand.Brand.Constructor<Int>
Int = import Brand
Brand.function refined<Int>(refinement: Predicate<number>, onFailure: (unbranded: number) => Brand.Brand<in out K extends string | symbol>.BrandErrors): Brand.Brand<in out K extends string | symbol>.Constructor<Int> (+1 overload)
Returns a `Brand.Constructor` that can construct a branded type from an unbranded value using the provided `refinement`
predicate as validation of the input data.
If you don't want to perform any validation but only distinguish between two values of the same type but with different meanings,
see
{@link
nominal
}
.
refined<type Int = number & Brand.Brand<"Int">
Int>(8 // Validation to ensure the value is an integer9 ((parameter) n: number
n) => var Number: NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.(method) NumberConstructor.isInteger(number: unknown): boolean
Returns true if the value passed is an integer, false otherwise.
isInteger((parameter) n: number
n),10 // Provide an error if validation fails11 ((parameter) n: number
n) => import Brand
Brand.const error: (message: string, meta?: unknown) => Brand.Brand<in out K extends string | symbol>.BrandErrors
Returns a `BrandErrors` that contains a single `RefinementError`.
error(`Expected ${(parameter) n: number
n} to be an integer`)12)
Usage example of the Int
constructor:
1import { import Brand
Brand } from "effect"2
3type type Int = number & Brand.Brand<"Int">
Int = number & import Brand
Brand.interface Brand<in out K extends string | symbol>
namespace Brand
A generic interface that defines a branded type.
Brand<"Int">4
5const const Int: Brand.Brand.Constructor<Int>
Int = import Brand
Brand.function refined<Int>(refinement: Predicate<number>, onFailure: (unbranded: number) => Brand.Brand<in out K extends string | symbol>.BrandErrors): Brand.Brand<in out K extends string | symbol>.Constructor<Int> (+1 overload)
Returns a `Brand.Constructor` that can construct a branded type from an unbranded value using the provided `refinement`
predicate as validation of the input data.
If you don't want to perform any validation but only distinguish between two values of the same type but with different meanings,
see
{@link
nominal
}
.
refined<type Int = number & Brand.Brand<"Int">
Int>(6 ((parameter) n: number
n) => var Number: NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.(method) NumberConstructor.isInteger(number: unknown): boolean
Returns true if the value passed is an integer, false otherwise.
isInteger((parameter) n: number
n), // Check if the value is an integer7 ((parameter) n: number
n) => import Brand
Brand.const error: (message: string, meta?: unknown) => Brand.Brand<in out K extends string | symbol>.BrandErrors
Returns a `BrandErrors` that contains a single `RefinementError`.
error(`Expected ${(parameter) n: number
n} to be an integer`) // Error message if the value is not an integer8)9
10// Create a valid Int value11const const x: Int
x: type Int = number & Brand.Brand<"Int">
Int = const Int: Brand.Brand<in out K extends string | symbol>.Constructor
(args: number) => Int
Constructs a branded type from a value of type `A`, throwing an error if
the provided `A` is not valid.
Int(3)12namespace console
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```
console.(method) Console.log(message?: any, ...optionalParams: any[]): void
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log(const x: Int
x) // Output: 313
14// Attempt to create an Int with an invalid value15const const y: Int
y: type Int = number & Brand.Brand<"Int">
Int = const Int: Brand.Brand<in out K extends string | symbol>.Constructor
(args: number) => Int
Constructs a branded type from a value of type `A`, throwing an error if
the provided `A` is not valid.
Int(3.14) // throws [ { message: 'Expected 3.14 to be an integer' } ]
Attempting to assign a non-Int
value will result in a compile-time error:
1import { import Brand
Brand } from "effect"2
3type type Int = number & Brand.Brand<"Int">
Int = number & import Brand
Brand.interface Brand<in out K extends string | symbol>
namespace Brand
A generic interface that defines a branded type.
Brand<"Int">4
5const const Int: Brand.Brand.Constructor<Int>
Int = import Brand
Brand.function refined<Int>(refinement: Predicate<number>, onFailure: (unbranded: number) => Brand.Brand<in out K extends string | symbol>.BrandErrors): Brand.Brand<in out K extends string | symbol>.Constructor<Int> (+1 overload)
Returns a `Brand.Constructor` that can construct a branded type from an unbranded value using the provided `refinement`
predicate as validation of the input data.
If you don't want to perform any validation but only distinguish between two values of the same type but with different meanings,
see
{@link
nominal
}
.
refined<type Int = number & Brand.Brand<"Int">
Int>(6 ((parameter) n: number
n) => var Number: NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.(method) NumberConstructor.isInteger(number: unknown): boolean
Returns true if the value passed is an integer, false otherwise.
isInteger((parameter) n: number
n),7 ((parameter) n: number
n) => import Brand
Brand.const error: (message: string, meta?: unknown) => Brand.Brand<in out K extends string | symbol>.BrandErrors
Returns a `BrandErrors` that contains a single `RefinementError`.
error(`Expected ${(parameter) n: number
n} to be an integer`)8)9
10// Correct usage11const const good: Int
good: type Int = number & Brand.Brand<"Int">
Int = const Int: Brand.Brand<in out K extends string | symbol>.Constructor
(args: number) => Int
Constructs a branded type from a value of type `A`, throwing an error if
the provided `A` is not valid.
Int(3)12
13// Incorrect, will result in an error14// @ts-expect-error15const const bad1: Int
bad1: type Int = number & Brand.Brand<"Int">
Int = 316
17// Also incorrect, will result in an error18// @ts-expect-error19const const bad2: Int
bad2: type Int = number & Brand.Brand<"Int">
Int = 3.14
In some scenarios, you may need to combine multiple branded types together. The Brand module provides the all
API to facilitate this:
1import { import Brand
Brand } from "effect"2
3type type Int = number & Brand.Brand<"Int">
Int = number & import Brand
Brand.interface Brand<in out K extends string | symbol>
namespace Brand
A generic interface that defines a branded type.
Brand<"Int">4
5const const Int: Brand.Brand.Constructor<Int>
Int = import Brand
Brand.function refined<Int>(refinement: Predicate<number>, onFailure: (unbranded: number) => Brand.Brand<in out K extends string | symbol>.BrandErrors): Brand.Brand<in out K extends string | symbol>.Constructor<Int> (+1 overload)
Returns a `Brand.Constructor` that can construct a branded type from an unbranded value using the provided `refinement`
predicate as validation of the input data.
If you don't want to perform any validation but only distinguish between two values of the same type but with different meanings,
see
{@link
nominal
}
.
refined<type Int = number & Brand.Brand<"Int">
Int>(6 ((parameter) n: number
n) => var Number: NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.(method) NumberConstructor.isInteger(number: unknown): boolean
Returns true if the value passed is an integer, false otherwise.
isInteger((parameter) n: number
n),7 ((parameter) n: number
n) => import Brand
Brand.const error: (message: string, meta?: unknown) => Brand.Brand<in out K extends string | symbol>.BrandErrors
Returns a `BrandErrors` that contains a single `RefinementError`.
error(`Expected ${(parameter) n: number
n} to be an integer`)8)9
10type type Positive = number & Brand.Brand<"Positive">
Positive = number & import Brand
Brand.interface Brand<in out K extends string | symbol>
namespace Brand
A generic interface that defines a branded type.
Brand<"Positive">11
12const const Positive: Brand.Brand.Constructor<Positive>
Positive = import Brand
Brand.function refined<Positive>(refinement: Predicate<number>, onFailure: (unbranded: number) => Brand.Brand<in out K extends string | symbol>.BrandErrors): Brand.Brand<in out K extends string | symbol>.Constructor<Positive> (+1 overload)
Returns a `Brand.Constructor` that can construct a branded type from an unbranded value using the provided `refinement`
predicate as validation of the input data.
If you don't want to perform any validation but only distinguish between two values of the same type but with different meanings,
see
{@link
nominal
}
.
refined<type Positive = number & Brand.Brand<"Positive">
Positive>(13 ((parameter) n: number
n) => (parameter) n: number
n > 0,14 ((parameter) n: number
n) => import Brand
Brand.const error: (message: string, meta?: unknown) => Brand.Brand<in out K extends string | symbol>.BrandErrors
Returns a `BrandErrors` that contains a single `RefinementError`.
error(`Expected ${(parameter) n: number
n} to be positive`)15)16
17// Combine the Int and Positive constructors into a new branded constructor PositiveInt18const const PositiveInt: Brand.Brand.Constructor<number & Brand.Brand<"Int"> & Brand.Brand<"Positive">>
PositiveInt = import Brand
Brand.const all: <[Brand.Brand<in out K extends string | symbol>.Constructor<Int>, Brand.Brand.Constructor<Positive>]>(brands_0: Brand.Brand.Constructor<Int>, brands_1: Brand.Brand.Constructor<...>) => Brand.Brand.Constructor<...>
Combines two or more brands together to form a single branded type.
This API is useful when you want to validate that the input data passes multiple brand validators.
all(const Int: Brand.Brand.Constructor<Int>
Int, const Positive: Brand.Brand.Constructor<Positive>
Positive)19
20// Extract the branded type from the PositiveInt constructor21type type PositiveInt = number & Brand.Brand<"Int"> & Brand.Brand<"Positive">
PositiveInt = import Brand
Brand.namespace Brand
A generic interface that defines a branded type.
Brand.type Brand<in out K extends string | symbol>.FromConstructor<A> = A extends Brand.Brand.Constructor<infer B extends Brand.Brand<any>> ? B : never
A utility type to extract a branded type from a `Brand.Constructor`.
FromConstructor<typeof const PositiveInt: Brand.Brand.Constructor<number & Brand.Brand<"Int"> & Brand.Brand<"Positive">>
PositiveInt>22
23// Usage example24
25// Valid positive integer26const const good: number & Brand.Brand<"Int"> & Brand.Brand<"Positive">
good: type PositiveInt = number & Brand.Brand<"Int"> & Brand.Brand<"Positive">
PositiveInt = const PositiveInt: Brand.Brand<in out K extends string | symbol>.Constructor
(args: number) => number & Brand.Brand<"Int"> & Brand.Brand<"Positive">
Constructs a branded type from a value of type `A`, throwing an error if
the provided `A` is not valid.
PositiveInt(10)27
28// throws [ { message: 'Expected -5 to be positive' } ]29const const bad1: number & Brand.Brand<"Int"> & Brand.Brand<"Positive">
bad1: type PositiveInt = number & Brand.Brand<"Int"> & Brand.Brand<"Positive">
PositiveInt = const PositiveInt: Brand.Brand<in out K extends string | symbol>.Constructor
(args: number) => number & Brand.Brand<"Int"> & Brand.Brand<"Positive">
Constructs a branded type from a value of type `A`, throwing an error if
the provided `A` is not valid.
PositiveInt(-5)30
31// throws [ { message: 'Expected 3.14 to be an integer' } ]32const const bad2: number & Brand.Brand<"Int"> & Brand.Brand<"Positive">
bad2: type PositiveInt = number & Brand.Brand<"Int"> & Brand.Brand<"Positive">
PositiveInt = const PositiveInt: Brand.Brand<in out K extends string | symbol>.Constructor
(args: number) => number & Brand.Brand<"Int"> & Brand.Brand<"Positive">
Constructs a branded type from a value of type `A`, throwing an error if
the provided `A` is not valid.
PositiveInt(3.14)