Either
Combining
Takes a structure of Eithers and returns an Either of values with the same structure.
- If a tuple is supplied, then the returned
Eitherwill contain a tuple with the same length. - If a struct is supplied, then the returned
Eitherwill contain a struct with the same keys. - If an iterable is supplied, then the returned
Eitherwill 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"))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
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
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'))fromOption
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'))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>Constructs a new Either holding a Right value. This usually represents a successful value due to the right bias
of this structure.
Signature
declare const right: <A>(a: A) => Either<A>Do Notation
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:
- Start the do simulation using the
Dovalue - Within the do simulation scope, you can use the
bindfunction to define variables and bind them toEithervalues - You can accumulate multiple
bindstatements to define multiple variables within the scope - Inside the do simulation scope, you can also use the
letfunction to define variables and bind them to simple values
See
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 }))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:
- Start the do simulation using the
Dovalue - Within the do simulation scope, you can use the
bindfunction to define variables and bind them toEithervalues - You can accumulate multiple
bindstatements to define multiple variables within the scope - Inside the do simulation scope, you can also use the
letfunction 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 }))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:
- Start the do simulation using the
Dovalue - Within the do simulation scope, you can use the
bindfunction to define variables and bind them toEithervalues - You can accumulate multiple
bindstatements to define multiple variables within the scope - Inside the do simulation scope, you can also use the
letfunction to define variables and bind them to simple values
See
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
getEquivalence
Signature
declare function getEquivalence<A, E>(__namedParameters: { left: Equivalence<E>; right: Equivalence<A>;}): Equivalence<Either<A, E>>Error Handling
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
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
Getters
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 | nullExample
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)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 getOrThrowWith.
Signature
declare const getOrThrow: <A, E>(self: Either<A, E>) => AExample
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")))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 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')))getOrUndefined
Signature
declare const getOrUndefined: <A, E>(self: Either<A, E>) => A | undefinedExample
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)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())Signature
declare const merge: <A, E>(self: Either<A, E>) => E | AGuards
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)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)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
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
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 > 0const 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
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>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>;}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>;}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
Signature
type Either<A, E = never> = Left<E, A> | Right<E, A>EitherUnify interface
Signature
interface EitherUnify<A extends { [typeSymbol]?: any;}> { Either?: () => A[typeof typeSymbol] extends Either<R0, L0> | _ ? Either<R0, L0> : never;}EitherUnifyIgnore interface
Signature
interface EitherUnifyIgnore { Effect?: true; Option?: true; Tag?: true;}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>>;}Signature
interface Right<out E, out A> extends Pipeable, Inspectable, STM<A, E>, Effect<A, E> { readonly _op: "Right"; readonly _tag: "Right"; 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<Right<E, A>>; readonly right: A; [iterator](): EffectGenerator<Right<E, A>>;}Optional Wrapping & Unwrapping
transposeMapOption
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 } }transposeOption
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
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
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
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>;}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
Type Lambdas
EitherTypeLambda interface
Signature
interface EitherTypeLambda extends TypeLambda { readonly type: Either<unknown, unknown>;}