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 [ReadonlyArray<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<Array<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 { Either } from "effect"

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, L | L2>
  <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 { Either } from "effect"

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 { Either, Option } from "effect"

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>

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

The “do simulation” in Effect allows you to write code in a more declarative style, similar to the “do notation” in other programming languages. It provides a way to define variables and perform operations on them using functions like bind and let.

Here’s how the do simulation works:

  1. Start the do simulation using the Do value
  2. Within the do simulation scope, you can use the bind function to define variables and bind them to Either values
  3. You can accumulate multiple bind statements to define multiple variables within the scope
  4. Inside the do simulation scope, you can also use the let function to define variables and bind them to simple values

Signature

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

Example

import { Either, pipe } from "effect"

const result = pipe(
  Either.Do,
  Either.bind("x", () => Either.right(2)),
  Either.bind("y", () => Either.right(3)),
  Either.let("sum", ({ x, y }) => x + y)
)
assert.deepStrictEqual(result, Either.right({ x: 2, y: 3, sum: 5 }))

Added in v2.0.0

bind

The “do simulation” in Effect allows you to write code in a more declarative style, similar to the “do notation” in other programming languages. It provides a way to define variables and perform operations on them using functions like bind and let.

Here’s how the do simulation works:

  1. Start the do simulation using the Do value
  2. Within the do simulation scope, you can use the bind function to define variables and bind them to Either values
  3. You can accumulate multiple bind statements to define multiple variables within the scope
  4. Inside the do simulation scope, you can also use the let function to define variables and bind them to simple values

Signature

export declare const bind: {
  <N extends string, A extends object, B, L2>(
    name: Exclude<N, keyof A>,
    f: (a: NoInfer<A>) => Either<B, L2>
  ): <L1>(self: Either<A, L1>) => Either<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, L1 | L2>
  <A extends object, L1, N extends string, B, L2>(
    self: Either<A, L1>,
    name: Exclude<N, keyof A>,
    f: (a: NoInfer<A>) => Either<B, L2>
  ): Either<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, L1 | L2>
}

Example

import { Either, pipe } from "effect"

const result = pipe(
  Either.Do,
  Either.bind("x", () => Either.right(2)),
  Either.bind("y", () => Either.right(3)),
  Either.let("sum", ({ x, y }) => x + y)
)
assert.deepStrictEqual(result, Either.right({ x: 2, y: 3, sum: 5 }))

Added in v2.0.0

bindTo

The “do simulation” in Effect allows you to write code in a more declarative style, similar to the “do notation” in other programming languages. It provides a way to define variables and perform operations on them using functions like bind and let.

Here’s how the do simulation works:

  1. Start the do simulation using the Do value
  2. Within the do simulation scope, you can use the bind function to define variables and bind them to Either values
  3. You can accumulate multiple bind statements to define multiple variables within the scope
  4. Inside the do simulation scope, you can also use the let function to define variables and bind them to simple values

Signature

export declare const bindTo: {
  <N extends string>(name: N): <R, L>(self: Either<R, L>) => Either<{ [K in N]: R }, L>
  <R, L, N extends string>(self: Either<R, L>, name: N): Either<{ [K in N]: R }, L>
}

Example

import { Either, pipe } from "effect"

const result = pipe(
  Either.Do,
  Either.bind("x", () => Either.right(2)),
  Either.bind("y", () => Either.right(3)),
  Either.let("sum", ({ x, y }) => x + y)
)
assert.deepStrictEqual(result, Either.right({ x: 2, y: 3, sum: 5 }))

Added in v2.0.0

let

The “do simulation” in Effect allows you to write code in a more declarative style, similar to the “do notation” in other programming languages. It provides a way to define variables and perform operations on them using functions like bind and let.

Here’s how the do simulation works:

  1. Start the do simulation using the Do value
  2. Within the do simulation scope, you can use the bind function to define variables and bind them to Either values
  3. You can accumulate multiple bind statements to define multiple variables within the scope
  4. Inside the do simulation scope, you can also use the let function to define variables and bind them to simple values

Signature

export declare const let: {
  <N extends string, R extends object, B>(
    name: Exclude<N, keyof R>,
    f: (r: NoInfer<R>) => B
  ): <L>(self: Either<R, L>) => Either<{ [K in N | keyof R]: K extends keyof R ? R[K] : B }, L>
  <R extends object, L, N extends string, B>(
    self: Either<R, L>,
    name: Exclude<N, keyof R>,
    f: (r: NoInfer<R>) => B
  ): Either<{ [K in N | keyof R]: K extends keyof R ? R[K] : B }, L>
}

Example

import { Either, pipe } from "effect"

const result = pipe(
  Either.Do,
  Either.bind("x", () => Either.right(2)),
  Either.bind("y", () => Either.right(3)),
  Either.let("sum", ({ x, y }) => x + y)
)
assert.deepStrictEqual(result, Either.right({ x: 2, y: 3, sum: 5 }))

Added in v2.0.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<R | R2, 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 { pipe, Either } from "effect"

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

assert.deepStrictEqual(
  pipe(
    Either.right(1),
    Either.filterOrLeft(isPositive, (n) => `${n} is not positive`)
  ),
  Either.right(1)
)
assert.deepStrictEqual(
  pipe(
    Either.right(0),
    Either.filterOrLeft(isPositive, (n) => `${n} is not positive`)
  ),
  Either.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 { Either, Option } from "effect"

assert.deepStrictEqual(Either.getLeft(Either.right("ok")), Option.none())
assert.deepStrictEqual(Either.getLeft(Either.left("err")), Option.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 { Either } from "effect"

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 { Either } from "effect"

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 { Either } from "effect"

assert.deepStrictEqual(Either.getOrThrow(Either.right(1)), 1)
assert.throws(() => Either.getOrThrow(Either.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 { Either } from "effect"

assert.deepStrictEqual(
  Either.getOrThrowWith(Either.right(1), () => new Error("Unexpected Left")),
  1
)
assert.throws(() => Either.getOrThrowWith(Either.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 { Either } from "effect"

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.

Signature

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

Example

import { Either, Option } from "effect"

assert.deepStrictEqual(Either.getRight(Either.right("ok")), Option.some("ok"))
assert.deepStrictEqual(Either.getRight(Either.left("err")), Option.none())

Added in v2.0.0

merge

Signature

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

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 { Either } from "effect"

assert.deepStrictEqual(Either.isEither(Either.right(1)), true)
assert.deepStrictEqual(Either.isEither(Either.left("a")), true)
assert.deepStrictEqual(Either.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 { Either } from "effect"

assert.deepStrictEqual(Either.isLeft(Either.right(1)), false)
assert.deepStrictEqual(Either.isLeft(Either.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 { Either } from "effect"

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

Added in v2.0.0

lifting

liftPredicate

Transforms a Predicate function into a Right of the input value if the predicate returns true or Left of the result of the provided function if the predicate returns false

Signature

export declare const liftPredicate: {
  <A, B extends A, E>(refinement: Refinement<NoInfer<A>, B>, orLeftWith: (a: NoInfer<A>) => E): (a: A) => Either<B, E>
  <A, E>(predicate: Predicate<NoInfer<A>>, orLeftWith: (a: NoInfer<A>) => E): (a: A) => Either<A, E>
  <A, E, B extends A>(self: A, refinement: Refinement<A, B>, orLeftWith: (a: A) => E): Either<B, E>
  <A, E>(self: A, predicate: Predicate<NoInfer<A>>, orLeftWith: (a: NoInfer<A>) => E): Either<A, E>
}

Example

import { pipe, Either } from "effect"

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

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

Added in v3.4.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 { pipe, Either } from "effect"

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

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

assert.deepStrictEqual(pipe(Either.right(1), Either.match({ onLeft, onRight })), "Ok: 1")
assert.deepStrictEqual(
  pipe(Either.left(["string 1", "string 2"]), Either.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, L | L2>
  <R2, L2>(f: Either<R2, L2>): <L, R1>(self: Either<R1, L>) => Either<R2, L | L2>
  <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, L | L2>
  <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