Skip to content
Effect 4.0 is here. One ecosystem. Zero dependencies.

Brand

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.

13 exports Since v2.0.0 Source

Alias

Since v2.0.0

Signature

type Branded<A, K extends string | symbol> = A & Brand<K>

Combining

Since v2.0.0

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.

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>>

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))

Constructors

Since v2.0.0

Returns a BrandErrors that contains a single RefinementError.

Signature

declare function error(message: string, meta?: unknown): BrandErrors
Since v2.0.0

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

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.

Signature

declare function nominal<A extends Brand<any>>(): Constructor<A>

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
Since v2.0.0

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.

Signature

declare function refined<A extends Brand<any>>(f: (unbranded: Unbranded<A>) => Option<BrandErrors>): Constructor<A>
declare function refined<A extends Brand<any>>(refinement: Predicate<Unbranded<A>>, onFailure: (unbranded: Unbranded<A>) => BrandErrors): Constructor<A>

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))

Getters

Since v3.15.0

Retrieves the unbranded value from a Brand instance.

Signature

declare const unbranded: <A extends Brand<any>>(branded: A) => Brand.Unbranded<A>

Models

Brand

interface
Since v2.0.0

A generic interface that defines a branded type.

Signature

interface Brand<in out K extends string | symbol> {
readonly [BrandTypeId]: { [k in string | symbol]: K };
}

Other

Since v2.0.0

Symbols

Signature

declare const BrandTypeId: unique symbol
Since v2.0.0

Signature

type BrandTypeId = typeof BrandTypeId

Signature

declare const RefinedConstructorsTypeId: unique symbol

Signature

type RefinedConstructorsTypeId = typeof RefinedConstructorsTypeId