Brand.ts overview
This module provides types and utility functions to create and work with branded types, which are TypeScript types with an added type tag to prevent accidental usage of a value in the wrong context.
The refined
and nominal
functions are both used to create branded types in TypeScript. The main difference between them is that refined
allows for validation of the data, while nominal
does not.
The nominal
function is used to create a new branded type that has the same underlying type as the input, but with a different name. This is useful when you want to distinguish between two values of the same type that have different meanings. The nominal
function does not perform any validation of the input data.
On the other hand, the refined
function is used to create a new branded type that has the same underlying type as the input, but with a different name, and it also allows for validation of the input data. The refined
function takes a predicate that is used to validate the input data. If the input data fails the validation, a BrandErrors
is returned, which provides information about the specific validation failure.
Since v2.0.0
Exports Grouped by Category
alias
Branded (type alias)
Signature
type Branded<A, K> = A & Brand<K>
Since v2.0.0
combining
all
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.
Example
import * as assert from "node:assert"
import { Brand } from "effect"
type Int = number & Brand.Brand<"Int">
const Int = Brand.refined<Int>(
(n) => Number.isInteger(n),
(n) => Brand.error(`Expected ${n} to be an integer`)
)
type Positive = number & Brand.Brand<"Positive">
const Positive = Brand.refined<Positive>(
(n) => n > 0,
(n) => Brand.error(`Expected ${n} to be positive`)
)
const PositiveInt = Brand.all(Int, Positive)
console.log(PositiveInt(1))
// 1
assert.throws(() => PositiveInt(1.1))
Signature
declare const all: <Brands extends readonly [Brand.Constructor<any>, ...Array<Brand.Constructor<any>>]>(
...brands: Brand.EnsureCommonBase<Brands>
) => Brand.Constructor<
Types.UnionToIntersection<{ [B in keyof Brands]: Brand.FromConstructor<Brands[B]> }[number]> extends infer X extends
Brand<any>
? X
: Brand<any>
>
Since v2.0.0
constructors
error
Returns a BrandErrors
that contains a single RefinementError
.
Signature
declare const error: (message: string, meta?: unknown) => Brand.BrandErrors
Since v2.0.0
errors
Takes a variable number of BrandErrors
and returns a single BrandErrors
that contains all refinement errors.
Signature
declare const errors: (...errors: Array<Brand.BrandErrors>) => Brand.BrandErrors
Since v2.0.0
nominal
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 refined
.
Example
import * as assert from "node:assert"
import { Brand } from "effect"
type UserId = number & Brand.Brand<"UserId">
const UserId = Brand.nominal<UserId>()
console.log(UserId(1))
// 1
Signature
declare const nominal: <A extends Brand<any>>() => Brand.Constructor<A>
Since v2.0.0
refined
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 nominal
.
Example
import * as assert from "node:assert"
import { Brand } from "effect"
type Int = number & Brand.Brand<"Int">
const Int = Brand.refined<Int>(
(n) => Number.isInteger(n),
(n) => Brand.error(`Expected ${n} to be an integer`)
)
console.log(Int(1))
// 1
assert.throws(() => Int(1.1))
Signature
declare const refined: {
<A extends Brand<any>>(f: (unbranded: Brand.Unbranded<A>) => Option.Option<Brand.BrandErrors>): Brand.Constructor<A>
<A extends Brand<any>>(
refinement: Predicate<Brand.Unbranded<A>>,
onFailure: (unbranded: Brand.Unbranded<A>) => Brand.BrandErrors
): Brand.Constructor<A>
}
Since v2.0.0
getters
unbranded
Retrieves the unbranded value from a Brand
instance.
Signature
declare const unbranded: <A extends Brand<any>>(branded: A) => Brand.Unbranded<A>
Since v3.15.0
models
Brand (interface)
A generic interface that defines a branded type.
Signature
export interface Brand<in out K extends string | symbol> {
readonly [BrandTypeId]: {
readonly [k in K]: K
}
}
Since v2.0.0
symbols
BrandTypeId
Signature
declare const BrandTypeId: unique symbol
Since v2.0.0
BrandTypeId (type alias)
Signature
type BrandTypeId = typeof BrandTypeId
Since v2.0.0
RefinedConstructorsTypeId
Signature
declare const RefinedConstructorsTypeId: unique symbol
Since v2.0.0
RefinedConstructorsTypeId (type alias)
Signature
type RefinedConstructorsTypeId = typeof RefinedConstructorsTypeId
Since v2.0.0
utils
Brand (namespace)
Since v2.0.0
BrandErrors (interface)
Represents a list of refinement errors.
Signature
export interface BrandErrors extends Array<RefinementError> {}
Since v2.0.0
RefinementError (interface)
Represents an error that occurs when the provided value of the branded type does not pass the refinement predicate.
Signature
export interface RefinementError {
readonly meta: unknown
readonly message: string
}
Since v2.0.0
Constructor (interface)
Signature
export interface Constructor<in out A extends Brand<any>> {
readonly [RefinedConstructorsTypeId]: RefinedConstructorsTypeId
/**
* Constructs a branded type from a value of type `A`, throwing an error if
* the provided `A` is not valid.
*/
(args: Brand.Unbranded<A>): A
/**
* Constructs a branded type from a value of type `A`, returning `Some<A>`
* if the provided `A` is valid, `None` otherwise.
*/
option(args: Brand.Unbranded<A>): Option.Option<A>
/**
* Constructs a branded type from a value of type `A`, returning `Right<A>`
* if the provided `A` is valid, `Left<BrandError>` otherwise.
*/
either(args: Brand.Unbranded<A>): Either.Either<A, Brand.BrandErrors>
/**
* Attempts to refine the provided value of type `A`, returning `true` if
* the provided `A` is valid, `false` otherwise.
*/
is(a: Brand.Unbranded<A>): a is Brand.Unbranded<A> & A
}
Since v2.0.0
FromConstructor (type alias)
A utility type to extract a branded type from a Brand.Constructor
.
Signature
type FromConstructor<A> = A extends Brand.Constructor<infer B> ? B : never
Since v2.0.0
Unbranded (type alias)
A utility type to extract the value type from a brand.
Signature
type Unbranded<P> = P extends infer Q & Brands<P> ? Q : P
Since v2.0.0
Brands (type alias)
A utility type to extract the brands from a branded type.
Signature
type Brands<P> =
P extends Brand<any>
? Types.UnionToIntersection<
{
[k in keyof P[BrandTypeId]]: k extends string | symbol ? Brand<k> : never
}[keyof P[BrandTypeId]]
>
: never
Since v2.0.0
EnsureCommonBase (type alias)
A utility type that checks that all brands have the same base type.
Signature
type EnsureCommonBase<Brands> = {
[B in keyof Brands]: Brand.Unbranded<Brand.FromConstructor<Brands[0]>> extends Brand.Unbranded<
Brand.FromConstructor<Brands[B]>
>
? Brand.Unbranded<Brand.FromConstructor<Brands[B]>> extends Brand.Unbranded<Brand.FromConstructor<Brands[0]>>
? Brands[B]
: Brands[B]
: "ERROR: All brands should have the same base type"
}
Since v2.0.0