Either
Combining
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:
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 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:
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 }))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 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
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
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 | 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)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>) => 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")))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 | 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)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 | A;Guards
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 > 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
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>;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 Right the inner value is applied to the onRight` 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>;
}Zipping
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>;
};
Takes a structure of
Eithers and returns anEitherof 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 returnedEitherwill contain a struct with the same keys. - If an iterable is supplied, then the returnedEitherwill contain an array.