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

Either

47 exports Since v2.0.0 Source

Combining

Since v2.0.0

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

declare const all: <I extends Iterable<Either<any, any>> | Record<string, Either<any, any>>>(input: I) => [I] extends [ReadonlyArray<Either<any, any>>] ? Either<{ [K in keyof I]: [I[K]] extends [Either<infer A, any>] ? A : never }, I[number] extends never ? never : [I[number]] extends [Either<any, infer E>] ? E : never> : [I] extends [Iterable<Either<infer A, infer E>>] ? Either<Array<A>, E> : Either<{ [K in keyof I]: [I[K]] extends [Either<infer A, any>] ? A : never }, I[keyof I] extends never ? never : [I[keyof I]] extends [Either<any, infer E>] ? E : never>

Example

import * as assert from "node:assert"
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"))
Since v2.0.0

Signature

declare const ap: {
<A, E2>(that: Either<A, E2>): <A2, E>(self: Either<(right: A) => A2, E>) => Either<A2, E2 | E>;
<A, A2, E, E2>(self: Either<(right: A) => A2, E>, that: Either<A, E2>): Either<A2, E | E2>;
}

Constructors

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

declare const fromNullable: {
<A, E>(onNullable: (right: A) => E): (self: A) => Either<NonNullable<A>, E>;
<A, E>(self: A, onNullable: (right: A) => E): Either<NonNullable<A>, E>;
}

Example

import * as assert from "node:assert"
import { Either } from "effect"
assert.deepStrictEqual(Either.fromNullable(1, () => 'fallback'), Either.right(1))
assert.deepStrictEqual(Either.fromNullable(null, () => 'fallback'), Either.left('fallback'))

Signature

declare const fromOption: {
<E>(onNone: () => E): <A>(self: Option<A>) => Either<A, E>;
<A, E>(self: Option<A>, onNone: () => E): Either<A, E>;
}

Example

import * as assert from "node:assert"
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'))
Since v2.0.0

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

Signature

declare const left: <E>(e: E) => Either<never, E>

Do Notation

Since v2.0.0

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

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

Example

import * as assert from "node:assert"
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 }))
Since v2.0.0

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

See

Signature

declare const bindTo: {
<N extends string>(name: N): <A, E>(self: Either<A, E>) => Either<{ [K in string]: A }, E>;
<A, E, N extends string>(self: Either<A, E>, name: N): Either<{ [K in string]: A }, E>;
}

Example

import * as assert from "node:assert"
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 }))
Since v2.0.0

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

declare const Do: Either<{}>

Example

import * as assert from "node:assert"
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 }))

Equivalence

Signature

declare function getEquivalence<A, E>(__namedParameters: {
left: Equivalence<E>;
right: Equivalence<A>;
}): Equivalence<Either<A, E>>

Error Handling

Since v2.0.0

Returns self if it is a Right or that otherwise.

Signature

declare const orElse: {
<E, A2, E2>(that: (left: E) => Either<A2, E2>): <A>(self: Either<A, E>) => Either<A2 | A, E2>;
<A, E, A2, E2>(self: Either<A, E>, that: (left: E) => Either<A2, E2>): Either<A | A2, E2>;
}

Filtering & Conditionals

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

Signature

declare const filterOrLeft: {
<A, B, E2>(refinement: Refinement<NoInfer<A>, B>, orLeftWith: (right: NoInfer<A>) => E2): <E>(self: Either<A, E>) => Either<B, E2 | E>;
<A, E2>(predicate: Predicate<NoInfer<A>>, orLeftWith: (right: NoInfer<A>) => E2): <E>(self: Either<A, E>) => Either<A, E2 | E>;
<A, E, B, E2>(self: Either<A, E>, refinement: Refinement<A, B>, orLeftWith: (right: A) => E2): Either<B, E | E2>;
<A, E, E2>(self: Either<A, E>, predicate: Predicate<A>, orLeftWith: (right: A) => E2): Either<A, E | E2>;
}

Example

import * as assert from "node:assert"
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")
)

Generators

Since v2.0.0

Signature

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

Getters

Since v2.0.0

Converts a Either to an Option discarding the value.

Signature

declare const getLeft: <A, E>(self: Either<A, E>) => Option<E>

Example

import * as assert from "node:assert"
import { Either, Option } from "effect"
assert.deepStrictEqual(Either.getLeft(Either.right('ok')), Option.none())
assert.deepStrictEqual(Either.getLeft(Either.left('err')), Option.some('err'))

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

Signature

declare const getOrElse: {
<E, A2>(onLeft: (left: E) => A2): <A>(self: Either<A, E>) => A2 | A;
<A, E, A2>(self: Either<A, E>, onLeft: (left: E) => A2): A | A2;
}

Example

import * as assert from "node:assert"
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!")

Signature

declare const getOrNull: <A, E>(self: Either<A, E>) => A | null

Example

import * as assert from "node:assert"
import { Either } from "effect"
assert.deepStrictEqual(Either.getOrNull(Either.right(1)), 1)
assert.deepStrictEqual(Either.getOrNull(Either.left("a")), null)

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

Signature

declare const getOrThrow: <A, E>(self: Either<A, E>) => A

Example

import * as assert from "node:assert"
import { Either } from "effect"
assert.deepStrictEqual(Either.getOrThrow(Either.right(1)), 1)
assert.throws(() => Either.getOrThrow(Either.left("error")))

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

Signature

declare const getOrThrowWith: {
<E>(onLeft: (left: E) => unknown): <A>(self: Either<A, E>) => A;
<A, E>(self: Either<A, E>, onLeft: (left: E) => unknown): A;
}

Example

import * as assert from "node:assert"
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')))

Signature

declare const getOrUndefined: <A, E>(self: Either<A, E>) => A | undefined

Example

import * as assert from "node:assert"
import { Either } from "effect"
assert.deepStrictEqual(Either.getOrUndefined(Either.right(1)), 1)
assert.deepStrictEqual(Either.getOrUndefined(Either.left("a")), undefined)
Since v2.0.0

Converts a Either to an Option discarding the Left.

Signature

declare const getRight: <A, E>(self: Either<A, E>) => Option<A>

Example

import * as assert from "node:assert"
import { Either, Option } from "effect"
assert.deepStrictEqual(Either.getRight(Either.right('ok')), Option.some('ok'))
assert.deepStrictEqual(Either.getRight(Either.left('err')), Option.none())
Since v2.0.0

Signature

declare const merge: <A, E>(self: Either<A, E>) => E | A

Guards

Since v2.0.0

Tests if a value is a Either.

Signature

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

Example

import * as assert from "node:assert"
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)
Since v2.0.0

Determine if a Either is a Left.

Signature

declare const isLeft: <A, E>(self: Either<A, E>) => self is Left<E, A>

Example

import * as assert from "node:assert"
import { Either } from "effect"
assert.deepStrictEqual(Either.isLeft(Either.right(1)), false)
assert.deepStrictEqual(Either.isLeft(Either.left("a")), true)
Since v2.0.0

Determine if a Either is a Right.

Signature

declare const isRight: <A, E>(self: Either<A, E>) => self is Right<E, A>

Example

import * as assert from "node:assert"
import { Either } from "effect"
assert.deepStrictEqual(Either.isRight(Either.right(1)), true)
assert.deepStrictEqual(Either.isRight(Either.left("a")), false)

Lifting

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

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

Example

import * as assert from "node:assert"
import { pipe, Either } from "effect"
const isPositive = (n: number): boolean => n > 0
const isPositiveEither = Either.liftPredicate(isPositive, n => `${n} is not positive`)
assert.deepStrictEqual(
isPositiveEither(1),
Either.right(1)
)
assert.deepStrictEqual(
isPositiveEither(0),
Either.left("0 is not positive")
)

Mapping

Since v2.0.0

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

declare function flip<A, E>(self: Either<A, E>): Either<E, A>
Since v2.0.0

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

Signature

declare const map: {
<A, A2>(f: (right: A) => A2): <E>(self: Either<A, E>) => Either<A2, E>;
<A, E, A2>(self: Either<A, E>, f: (right: A) => A2): Either<A2, E>;
}
Since v2.0.0

Signature

declare const mapBoth: {
<E, E2, A, A2>(options: {
readonly onLeft: (left: E) => E2;
readonly onRight: (right: A) => A2;
}): (self: Either<A, E>) => Either<A2, E2>;
<A, E, E2, A2>(self: Either<A, E>, options: {
readonly onLeft: (left: E) => E2;
readonly onRight: (right: A) => A2;
}): Either<A2, E2>;
}
Since v2.0.0

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

Signature

declare const mapLeft: {
<E, E2>(f: (left: E) => E2): <A>(self: Either<A, E>) => Either<A, E2>;
<A, E, E2>(self: Either<A, E>, f: (left: E) => E2): Either<A, E2>;
}

Models

Since v2.0.0

Signature

type Either<A, E = never> = Left<E, A> | Right<E, A>

EitherUnify

interface
Since v2.0.0

Signature

interface EitherUnify<A extends {
[typeSymbol]?: any;
}> {
Either?: () => A[typeof typeSymbol] extends Either<R0, L0> | _ ? Either<R0, L0> : never;
}
Since v2.0.0

Signature

interface EitherUnifyIgnore {
Effect?: true;
Option?: true;
Tag?: true;
}

Left

interface
Since v2.0.0

Signature

interface Left<out E, out A> extends Pipeable, Inspectable, STM<A, E>, Effect<A, E> {
readonly _op: "Left";
readonly _tag: "Left";
readonly [ChannelTypeId]: VarianceStruct<never, unknown, E, unknown, A, unknown, never>;
readonly [EffectTypeId]: VarianceStruct<A, E, never>;
[ignoreSymbol]?: EitherUnifyIgnore;
readonly [SinkTypeId]: VarianceStruct<A, unknown, never, E, never>;
readonly [STMTypeId]: {
readonly _A: Covariant<A>;
readonly _E: Covariant<E>;
readonly _R: Covariant<never>;
};
readonly [StreamTypeId]: VarianceStruct<A, E, never>;
readonly [TypeId]: {
readonly _L: Covariant<E>;
readonly _R: Covariant<A>;
};
[typeSymbol]?: unknown;
[unifySymbol]?: EitherUnify<Left<E, A>>;
readonly left: E;
[iterator](): EffectGenerator<Left<E, A>>;
}

Optional Wrapping & Unwrapping

Applies an Either on an Option and transposes the result.

Details

If the Option is None, the resulting Either will immediately succeed with a Right value of None. If the Option is Some, the transformation function will be applied to the inner value, and its result wrapped in a Some.

Signature

declare const transposeMapOption: <A, B, E = never>(f: (self: A) => Either<B, E>) => (self: Option<A>) => Either<Option<B>, E> & <A, B, E = never>(self: Option<A>, f: (self: A) => Either<B, E>) => Either<Option<B>, E>

Example

import { Either, Option, pipe } from "effect"
// โ”Œโ”€โ”€โ”€ Either<Option<number>, never>>
// โ–ผ
const noneResult = pipe(
Option.none(),
Either.transposeMapOption(() => Either.right(42)) // will not be executed
)
console.log(noneResult)
// Output: { _id: 'Either', _tag: 'Right', right: { _id: 'Option', _tag: 'None' } }
// โ”Œโ”€โ”€โ”€ Either<Option<number>, never>>
// โ–ผ
const someRightResult = pipe(
Option.some(42),
Either.transposeMapOption((value) => Either.right(value * 2))
)
console.log(someRightResult)
// Output: { _id: 'Either', _tag: 'Right', right: { _id: 'Option', _tag: 'Some', value: 84 } }

Converts an Option of an Either into an Either of an Option.

Details

This function transforms an Option<Either<A, E>> into an Either<Option<A>, E>. If the Option is None, the resulting Either will be a Right with a None value. If the Option is Some, the inner Either will be executed, and its result wrapped in a Some.

Signature

declare function transposeOption<A = never, E = never>(self: Option<Either<A, E>>): Either<Option<A>, E>

Example

import { Effect, Either, Option } from "effect"
// โ”Œโ”€โ”€โ”€ Option<Either<number, never>>
// โ–ผ
const maybe = Option.some(Either.right(42))
// โ”Œโ”€โ”€โ”€ Either<Option<number>, never, never>
// โ–ผ
const result = Either.transposeOption(maybe)
console.log(Effect.runSync(result))
// Output: { _id: 'Option', _tag: 'Some', value: 42 }

Other

Since v2.0.0

Signature

declare const let: {
<N extends string, A extends object, B>(name: Exclude<N, keyof A>, f: (r: NoInfer<A>) => B): <E>(self: Either<A, E>) => Either<{ [K in string | number | symbol]: K extends keyof A ? A[K] : B }, E>;
<A extends object, E, N extends string, B>(self: Either<A, E>, name: Exclude<N, keyof A>, f: (r: NoInfer<A>) => B): Either<{ [K in string | number | symbol]: K extends keyof A ? A[K] : B }, E>;
}

Signature

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

Signature

declare const void: Either<void>

Pattern Matching

Since v2.0.0

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

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

Example

import * as assert from "node:assert"
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'
)

Sequencing

Since v2.0.0

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

Signature

declare const andThen: {
<A, A2, E2>(f: (right: A) => Either<A2, E2>): <E>(self: Either<A, E>) => Either<A2, E2 | E>;
<A2, E2>(f: Either<A2, E2>): <E, A>(self: Either<A, E>) => Either<A2, E2 | E>;
<A, A2>(f: (right: A) => A2): <E>(self: Either<A, E>) => Either<A2, E>;
<A2>(right: NotFunction<A2>): <A, E>(self: Either<A, E>) => Either<A2, E>;
<A, E, A2, E2>(self: Either<A, E>, f: (right: A) => Either<A2, E2>): Either<A2, E | E2>;
<A, E, A2, E2>(self: Either<A, E>, f: Either<A2, E2>): Either<A2, E | E2>;
<A, E, A2>(self: Either<A, E>, f: (right: A) => A2): Either<A2, E>;
<A, E, A2>(self: Either<A, E>, f: NotFunction<A2>): Either<A2, E>;
}
Since v2.0.0

Signature

declare const flatMap: {
<A, A2, E2>(f: (right: A) => Either<A2, E2>): <E>(self: Either<A, E>) => Either<A2, E2 | E>;
<A, E, A2, E2>(self: Either<A, E>, f: (right: A) => Either<A2, E2>): Either<A2, E | E2>;
}

Symbols

Since v2.0.0

Signature

declare const TypeId: unique symbol
Since v2.0.0

Signature

type TypeId = typeof TypeId

Type Lambdas

Since v2.0.0

Signature

interface EitherTypeLambda extends TypeLambda {
readonly type: Either<unknown, unknown>;
}

Zipping

Since v2.0.0

Signature

declare const zipWith: {
<A2, E2, A, B>(that: Either<A2, E2>, f: (right: A, right2: A2) => B): <E>(self: Either<A, E>) => Either<B, E2 | E>;
<A, E, A2, E2, B>(self: Either<A, E>, that: Either<A2, E2>, f: (right: A, right2: A2) => B): Either<B, E | E2>;
}