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

Either overview

Added in v2.0.0


Table of contents


combining

all

Takes a structure of Eithers and returns an Either of values with the same structure.

  • If a tuple is supplied, then the returned Either will contain a tuple with the same length.
  • If a struct is supplied, then the returned Either will contain a struct with the same keys.
  • If an iterable is supplied, then the returned Either will contain an array.

Signature

export declare const all: <const I extends Iterable<Either<any, any>> | Record<string, Either<any, any>>>(
  input: I
) => [I] extends [readonly Either<any, any>[]]
  ? Either<
      { -readonly [K in keyof I]: [I[K]] extends [Either<infer R, any>] ? R : never },
      I[number] extends never ? never : [I[number]] extends [Either<any, infer L>] ? L : never
    >
  : [I] extends [Iterable<Either<infer R, infer L>>]
    ? Either<R[], L>
    : Either<
        { -readonly [K in keyof I]: [I[K]] extends [Either<infer R, any>] ? R : never },
        I[keyof I] extends never ? never : [I[keyof I]] extends [Either<any, infer L>] ? L : never
      >

Example

import * as Either from "effect/Either"

assert.deepStrictEqual(Either.all([Either.right(1), Either.right(2)]), Either.right([1, 2]))
assert.deepStrictEqual(
  Either.all({ right: Either.right(1), b: Either.right("hello") }),
  Either.right({ right: 1, b: "hello" })
)
assert.deepStrictEqual(Either.all({ right: Either.right(1), b: Either.left("error") }), Either.left("error"))

Added in v2.0.0

ap

Signature

export declare const ap: {
  <R, L2>(that: Either<R, L2>): <R2, L>(self: Either<(right: R) => R2, L>) => Either<R2, L2 | L>
  <R, R2, L, L2>(self: Either<(right: R) => R2, L>, that: Either<R, L2>): Either<R2, L | L2>
}

Added in v2.0.0

constructors

fromNullable

Takes a lazy default and a nullable value, if the value is not nully (null or undefined), turn it into a Right, if the value is nully use the provided default as a Left.

Signature

export declare const fromNullable: {
  <R, L>(onNullable: (right: R) => L): (self: R) => Either<NonNullable<R>, L>
  <R, L>(self: R, onNullable: (right: R) => L): Either<NonNullable<R>, L>
}

Example

import * as Either from "effect/Either"

assert.deepStrictEqual(
  Either.fromNullable(1, () => "fallback"),
  Either.right(1)
)
assert.deepStrictEqual(
  Either.fromNullable(null, () => "fallback"),
  Either.left("fallback")
)

Added in v2.0.0

fromOption

Signature

export declare const fromOption: {
  <L>(onNone: () => L): <R>(self: Option<R>) => Either<R, L>
  <R, L>(self: Option<R>, onNone: () => L): Either<R, L>
}

Example

import * as Either from "effect/Either"
import * as Option from "effect/Option"

assert.deepStrictEqual(
  Either.fromOption(Option.some(1), () => "error"),
  Either.right(1)
)
assert.deepStrictEqual(
  Either.fromOption(Option.none(), () => "error"),
  Either.left("error")
)

Added in v2.0.0

left

Constructs a new Either holding a Left value. This usually represents a failure, due to the right-bias of this structure.

Signature

export declare const left: <L>(left: L) => Either<never, L>

Added in v2.0.0

Constructs a new Either holding a Right value. This usually represents a successful value due to the right bias of this structure.

Signature

export declare const right: <R>(right: R) => Either<R, never>

Added in v2.0.0

try

Imports a synchronous side-effect into a pure Either value, translating any thrown exceptions into typed failed eithers creating with Either.left.

Signature

export declare const try: { <R, L>(options: { readonly try: LazyArg<R>; readonly catch: (error: unknown) => L; }): Either<R, L>; <R>(evaluate: LazyArg<R>): Either<R, unknown>; }

Added in v2.0.0

do notation

Do

Signature

export declare const Do: Either<{}, never>

Added in v2.4.0

bind

Binds an effectful value in a do scope

Signature

export declare const bind: {
  <N extends string, K, A, E2>(
    tag: Exclude<N, keyof K>,
    f: (_: K) => Either<A, E2>
  ): <E>(self: Either<K, E>) => Either<MergeRecord<K, { [k in N]: A }>, E2 | E>
  <K, E, N extends string, A, E2>(
    self: Either<E, K>,
    tag: Exclude<N, keyof K>,
    f: (_: K) => Either<A, E2>
  ): Either<MergeRecord<K, { [k in N]: A }>, E | E2>
}

Added in v2.4.0

bindTo

Signature

export declare const bindTo: {
  <N extends string>(tag: N): <A, E>(self: Either<A, E>) => Either<Record<N, A>, E>
  <A, E, N extends string>(self: Either<A, E>, tag: N): Either<Record<N, A>, E>
}

Added in v2.4.0

let

Like bind for values

Signature

export declare const let: {
  <N extends string, K, A>(
    tag: Exclude<N, keyof K>,
    f: (_: K) => A
  ): <E>(self: Either<K, E>) => Either<MergeRecord<K, { [k in N]: A }>, E>
  <K, E, N extends string, A>(
    self: Either<K, E>,
    tag: Exclude<N, keyof K>,
    f: (_: K) => A
  ): Either<MergeRecord<K, { [k in N]: A }>, E>
}

Added in v2.4.0

equivalence

getEquivalence

Signature

export declare const getEquivalence: <R, L>({
  left,
  right
}: {
  right: Equivalence.Equivalence<R>
  left: Equivalence.Equivalence<L>
}) => Equivalence.Equivalence<Either<R, L>>

Added in v2.0.0

error handling

orElse

Returns self if it is a Right or that otherwise.

Signature

export declare const orElse: {
  <L, R2, L2>(that: (left: L) => Either<R2, L2>): <R>(self: Either<R, L>) => Either<R2 | R, L2>
  <R, L, R2, L2>(self: Either<R, L>, that: (left: L) => Either<R2, L2>): Either<R | R2, L2>
}

Added in v2.0.0

filtering & conditionals

filterOrLeft

Filter the right value with the provided function. If the predicate fails, set the left value with the result of the provided function.

Signature

export declare const filterOrLeft: {
  <R, B extends R, L2>(
    refinement: Refinement<NoInfer<R>, B>,
    orLeftWith: (right: NoInfer<R>) => L2
  ): <L>(self: Either<R, L>) => Either<B, L2 | L>
  <R, L2>(
    predicate: Predicate<NoInfer<R>>,
    orLeftWith: (right: NoInfer<R>) => L2
  ): <L>(self: Either<R, L>) => Either<R, L2 | L>
  <R, L, B extends R, L2>(
    self: Either<R, L>,
    refinement: Refinement<R, B>,
    orLeftWith: (right: R) => L2
  ): Either<B, L | L2>
  <R, L, E2>(self: Either<R, L>, predicate: Predicate<R>, orLeftWith: (right: R) => E2): Either<R, L | E2>
}

Example

import * as E from "effect/Either"
import { pipe } from "effect/Function"

const isPositive = (n: number): boolean => n > 0

assert.deepStrictEqual(
  pipe(
    E.right(1),
    E.filterOrLeft(isPositive, (n) => `${n} is not positive`)
  ),
  E.right(1)
)
assert.deepStrictEqual(
  pipe(
    E.right(0),
    E.filterOrLeft(isPositive, (n) => `${n} is not positive`)
  ),
  E.left("0 is not positive")
)

Added in v2.0.0

generators

gen

Signature

export declare const gen: Gen.Gen<EitherTypeLambda, Gen.Adapter<EitherTypeLambda>>

Added in v2.0.0

getters

getLeft

Converts a Either to an Option discarding the value.

Signature

export declare const getLeft: <R, L>(self: Either<R, L>) => Option<L>

Example

import * as O from "effect/Option"
import * as E from "effect/Either"

assert.deepStrictEqual(E.getLeft(E.right("ok")), O.none())
assert.deepStrictEqual(E.getLeft(E.left("err")), O.some("err"))

Added in v2.0.0

getOrElse

Returns the wrapped value if it’s a Right or a default value if is a Left.

Signature

export declare const getOrElse: {
  <L, R2>(onLeft: (left: L) => R2): <R>(self: Either<R, L>) => R2 | R
  <R, L, R2>(self: Either<R, L>, onLeft: (left: L) => R2): R | R2
}

Example

import * as Either from "effect/Either"

assert.deepStrictEqual(
  Either.getOrElse(Either.right(1), (error) => error + "!"),
  1
)
assert.deepStrictEqual(
  Either.getOrElse(Either.left("not a number"), (error) => error + "!"),
  "not a number!"
)

Added in v2.0.0

getOrNull

Signature

export declare const getOrNull: <R, L>(self: Either<R, L>) => R | null

Example

import * as Either from "effect/Either"

assert.deepStrictEqual(Either.getOrNull(Either.right(1)), 1)
assert.deepStrictEqual(Either.getOrNull(Either.left("a")), null)

Added in v2.0.0

getOrThrow

Extracts the value of an Either or throws if the Either is Left.

The thrown error is a default error. To configure the error thrown, see {@link getOrThrowWith}.

Signature

export declare const getOrThrow: <R, L>(self: Either<R, L>) => R

Example

import * as E from "effect/Either"

assert.deepStrictEqual(E.getOrThrow(E.right(1)), 1)
assert.throws(() => E.getOrThrow(E.left("error")))

Added in v2.0.0

getOrThrowWith

Extracts the value of an Either or throws if the Either is Left.

If a default error is sufficient for your use case and you don’t need to configure the thrown error, see {@link getOrThrow}.

Signature

export declare const getOrThrowWith: {
  <L>(onLeft: (left: L) => unknown): <A>(self: Either<A, L>) => A
  <R, L>(self: Either<R, L>, onLeft: (left: L) => unknown): R
}

Example

import * as E from "effect/Either"

assert.deepStrictEqual(
  E.getOrThrowWith(E.right(1), () => new Error("Unexpected Left")),
  1
)
assert.throws(() => E.getOrThrowWith(E.left("error"), () => new Error("Unexpected Left")))

Added in v2.0.0

getOrUndefined

Signature

export declare const getOrUndefined: <R, L>(self: Either<R, L>) => R | undefined

Example

import * as Either from "effect/Either"

assert.deepStrictEqual(Either.getOrUndefined(Either.right(1)), 1)
assert.deepStrictEqual(Either.getOrUndefined(Either.left("a")), undefined)

Added in v2.0.0

getRight

Converts a Either to an Option discarding the Left.

Alias of {@link toOption}.

Signature

export declare const getRight: <R, L>(self: Either<R, L>) => Option<R>

Example

import * as O from "effect/Option"
import * as E from "effect/Either"

assert.deepStrictEqual(E.getRight(E.right("ok")), O.some("ok"))
assert.deepStrictEqual(E.getRight(E.left("err")), O.none())

Added in v2.0.0

merge

Signature

export declare const merge: <R, L>(self: Either<R, L>) => R | L

Added in v2.0.0

guards

isEither

Tests if a value is a Either.

Signature

export declare const isEither: (input: unknown) => input is Either<unknown, unknown>

Example

import { isEither, left, right } from "effect/Either"

assert.deepStrictEqual(isEither(right(1)), true)
assert.deepStrictEqual(isEither(left("a")), true)
assert.deepStrictEqual(isEither({ right: 1 }), false)

Added in v2.0.0

isLeft

Determine if a Either is a Left.

Signature

export declare const isLeft: <R, L>(self: Either<R, L>) => self is Left<L, R>

Example

import { isLeft, left, right } from "effect/Either"

assert.deepStrictEqual(isLeft(right(1)), false)
assert.deepStrictEqual(isLeft(left("a")), true)

Added in v2.0.0

isRight

Determine if a Either is a Right.

Signature

export declare const isRight: <R, L>(self: Either<R, L>) => self is Right<L, R>

Example

import { isRight, left, right } from "effect/Either"

assert.deepStrictEqual(isRight(right(1)), true)
assert.deepStrictEqual(isRight(left("a")), false)

Added in v2.0.0

mapping

flip

Returns an Either that swaps the error/success cases. This allows you to use all methods on the error channel, possibly before flipping back.

Signature

export declare const flip: <R, L>(self: Either<R, L>) => Either<L, R>

Added in v2.0.0

map

Maps the Right side of an Either value to a new Either value.

Signature

export declare const map: {
  <R, R2>(f: (right: R) => R2): <L>(self: Either<R, L>) => Either<R2, L>
  <R, L, R2>(self: Either<R, L>, f: (right: R) => R2): Either<R2, L>
}

Added in v2.0.0

mapBoth

Signature

export declare const mapBoth: {
  <L, L2, R, R2>(options: {
    readonly onLeft: (left: L) => L2
    readonly onRight: (right: R) => R2
  }): (self: Either<R, L>) => Either<R2, L2>
  <L, R, L2, R2>(
    self: Either<R, L>,
    options: { readonly onLeft: (left: L) => L2; readonly onRight: (right: R) => R2 }
  ): Either<R2, L2>
}

Added in v2.0.0

mapLeft

Maps the Left side of an Either value to a new Either value.

Signature

export declare const mapLeft: {
  <L, L2>(f: (left: L) => L2): <R>(self: Either<R, L>) => Either<R, L2>
  <R, L, L2>(self: Either<R, L>, f: (left: L) => L2): Either<R, L2>
}

Added in v2.0.0

models

Either (type alias)

Signature

export type Either<R, L = never> = Left<L, R> | Right<L, R>

Added in v2.0.0

EitherUnify (interface)

Signature

export interface EitherUnify<A extends { [Unify.typeSymbol]?: any }> {
  Either?: () => A[Unify.typeSymbol] extends Either<infer R0, infer L0> | infer _ ? Either<R0, L0> : never
}

Added in v2.0.0

EitherUnifyIgnore (interface)

Signature

export interface EitherUnifyIgnore {}

Added in v2.0.0

Left (interface)

Signature

export interface Left<out L, out R> extends Pipeable, Inspectable {
  readonly _tag: "Left"
  readonly _op: "Left"
  readonly left: L
  readonly [TypeId]: {
    readonly _R: Covariant<R>
    readonly _L: Covariant<L>
  }
  [Unify.typeSymbol]?: unknown
  [Unify.unifySymbol]?: EitherUnify<this>
  [Unify.ignoreSymbol]?: EitherUnifyIgnore
}

Added in v2.0.0

Right (interface)

Signature

export interface Right<out L, out R> extends Pipeable, Inspectable {
  readonly _tag: "Right"
  readonly _op: "Right"
  readonly right: R
  readonly [TypeId]: {
    readonly _R: Covariant<R>
    readonly _L: Covariant<L>
  }
  [Unify.typeSymbol]?: unknown
  [Unify.unifySymbol]?: EitherUnify<this>
  [Unify.ignoreSymbol]?: EitherUnifyIgnore
}

Added in v2.0.0

pattern matching

match

Takes two functions and an Either value, if the value is a Left the inner value is applied to the onLeft function, if the value is a Rightthe inner value is applied to theonRight` function.

Signature

export declare const match: {
  <L, B, R, C = B>(options: {
    readonly onLeft: (left: L) => B
    readonly onRight: (right: R) => C
  }): (self: Either<R, L>) => B | C
  <R, L, B, C = B>(
    self: Either<R, L>,
    options: { readonly onLeft: (left: L) => B; readonly onRight: (right: R) => C }
  ): B | C
}

Example

import * as E from "effect/Either"
import { pipe } from "effect/Function"

const onLeft = (strings: ReadonlyArray<string>): string => `strings: ${strings.join(", ")}`

const onRight = (value: number): string => `Ok: ${value}`

assert.deepStrictEqual(pipe(E.right(1), E.match({ onLeft, onRight })), "Ok: 1")
assert.deepStrictEqual(
  pipe(E.left(["string 1", "string 2"]), E.match({ onLeft, onRight })),
  "strings: string 1, string 2"
)

Added in v2.0.0

sequencing

andThen

Executes a sequence of two Eithers. The second Either can be dependent on the result of the first Either.

Signature

export declare const andThen: {
  <R, R2, L2>(f: (right: R) => Either<R2, L2>): <L>(self: Either<R, L>) => Either<R2, L2 | L>
  <R2, L2>(f: Either<R2, L2>): <L, R1>(self: Either<R1, L>) => Either<R2, L2 | L>
  <R, R2>(f: (right: R) => R2): <L>(self: Either<R, L>) => Either<R2, L>
  <R2>(right: NotFunction<R2>): <R1, L>(self: Either<R1, L>) => Either<R2, L>
  <R, L, R2, L2>(self: Either<R, L>, f: (right: R) => Either<R2, L2>): Either<R2, L | L2>
  <R, L, R2, L2>(self: Either<R, L>, f: Either<R2, L2>): Either<R2, L | L2>
  <R, L, R2>(self: Either<R, L>, f: (right: R) => R2): Either<R2, L>
  <R, L, R2>(self: Either<R, L>, f: NotFunction<R2>): Either<R2, L>
}

Added in v2.0.0

flatMap

Signature

export declare const flatMap: {
  <R, R2, L2>(f: (right: R) => Either<R2, L2>): <L>(self: Either<R, L>) => Either<R2, L2 | L>
  <R, L, R2, L2>(self: Either<R, L>, f: (right: R) => Either<R2, L2>): Either<R2, L | L2>
}

Added in v2.0.0

symbols

TypeId

Signature

export declare const TypeId: typeof TypeId

Added in v2.0.0

TypeId (type alias)

Signature

export type TypeId = typeof TypeId

Added in v2.0.0

type lambdas

EitherTypeLambda (interface)

Signature

export interface EitherTypeLambda extends TypeLambda {
  readonly type: Either<this["Target"], this["Out1"]>
}

Added in v2.0.0

utils

Either (namespace)

Added in v2.0.0

Left (type alias)

Signature

export type Left<T extends Either<any, any>> = [T] extends [Either<infer _A, infer _E>] ? _E : never

Added in v2.0.0

Right (type alias)

Signature

export type Right<T extends Either<any, any>> = [T] extends [Either<infer _A, infer _E>] ? _A : never

Added in v2.0.0

zipping

zipWith

Signature

export declare const zipWith: {
  <R2, L2, R, B>(that: Either<R2, L2>, f: (right: R, right2: R2) => B): <L>(self: Either<R, L>) => Either<B, L2 | L>
  <R, L, R2, L2, B>(self: Either<R, L>, that: Either<R2, L2>, f: (right: R, right2: R2) => B): Either<B, L | L2>
}

Added in v2.0.0