Skip to main content Link Search Menu Expand Document (external link)

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>

Source

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

Source

Since v2.0.0

constructors

error

Returns a BrandErrors that contains a single RefinementError.

Signature

declare const error: (message: string, meta?: unknown) => Brand.BrandErrors

Source

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

Source

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>

Source

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

Source

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>

Source

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

Source

Since v2.0.0

symbols

BrandTypeId

Signature

declare const BrandTypeId: unique symbol

Source

Since v2.0.0

BrandTypeId (type alias)

Signature

type BrandTypeId = typeof BrandTypeId

Source

Since v2.0.0

RefinedConstructorsTypeId

Signature

declare const RefinedConstructorsTypeId: unique symbol

Source

Since v2.0.0

RefinedConstructorsTypeId (type alias)

Signature

type RefinedConstructorsTypeId = typeof RefinedConstructorsTypeId

Source

Since v2.0.0

utils

Brand (namespace)

Source

Since v2.0.0

BrandErrors (interface)

Represents a list of refinement errors.

Signature

export interface BrandErrors extends Array<RefinementError> {}

Source

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
}

Source

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
}

Source

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

Source

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

Source

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

Source

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

Source

Since v2.0.0