@sweet-monads/either
v3.3.1
Published
Either monad
Downloads
26,106
Readme
@sweet-monads/either
Either Monad, The Either monad represents values with two possibilities: a value of type Either a b is either Left a or Right b.
This library belongs to sweet-monads project
sweet-monads — easy-to-use monads implementation with static types definition and separated packages.
- No dependencies, one small file
- Easily auditable TypeScript/JS code
- Check out all libraries: either, iterator, interfaces, maybe
Usage
npm install @sweet-monads/either
import { Either, right } from "@sweet-monads/either";
class UserNotFoundError extends Error {
name: "UserNotFoundError";
}
type User = { email: string; password: string };
function getUser(id: number): Either<UserNotFoundError, User> {
return right({ email: "[email protected]", password: "test" });
}
// Either<UserNotFoundError, string>
const user = getUser(1).map(({ email }) => email);
API
chain
merge
mergeInOne
mergeInMany
left
right
from
fromTry
fromPromise
isEither
Either#isLeft
Either#isRight
Either#or
Either#join
Either#map
Either#mapRight
Either#mapLeft
Either#asyncMap
Either#apply
Either#asyncApply
Either#chain
Either#asyncChain
Either#fold
- Helpers
chain
function chain<L, R, NL, NR>(fn: (v: R) => Promise<Either<NL, NR>>): (m: Either<L, R>) => Promise<Either<L | NL, NR>>;
fn: (v: R) => Promise<Either<NL, NR>>
- function which should be applied asynchronously toEither<L, R>
value- Returns function with
Either<L, R>
argument and promisedEither
with new error or mapped byfn
value (could be used insidePromise#then
function).
Example:
const getValue = async () => right(1);
// Either<TypeError, right>
const result = await getValue()
.then(Either.chain(async v => right(v * 2)))
.then(Either.chain(async v => left(new TypeError("Unexpected"))));
merge
Alias for mergeInOne
function merge<L1, R1>(values: [Either<L1, R1>]): Either<L1, [R1]>;
function merge<L1, R1, L2, R2>(values: [Either<L1, R1>, Either<L2, R2>]): Either<L1 | L2, [R1, R2]>;
function merge<L1, R1, L2, R2, L3, R3>(
values: [Either<L1, R1>, Either<L2, R2>, Either<L3, R3>]
): Either<L1 | L2 | L3, [R1, R2, R3]>;
// ... until 10 elements
values: Array<Either<L, R>>
- Array of Either values which will be merged into Either of Array- Returns
Either<L, Array<R>>
which will containRight<Array<R>>
if all of array elements wasRight<R>
otherwiseLeft<L>
.
Example:
const v1 = right<TypeError, number>(2); // Either<TypeError, number>.Right
const v2 = right<ReferenceError, string>("test"); // Either<ReferenceError, string>.Right
const v3 = left<Error, boolean>(new Error()); // Either<Error, boolean>.Left
merge([v1, v2]); // Either<TypeError | ReferenceError, [number, string]>.Right
merge([v1, v2, v3]); // Either<TypeError | ReferenceError | Error, [number, string, boolean]>.Left
mergeInOne
function merge<L1, R1>(values: [Either<L1, R1>]): Either<L1, [R1]>;
function merge<L1, R1, L2, R2>(values: [Either<L1, R1>, Either<L2, R2>]): Either<L1 | L2, [R1, R2]>;
function merge<L1, R1, L2, R2, L3, R3>(
values: [Either<L1, R1>, Either<L2, R2>, Either<L3, R3>]
): Either<L1 | L2 | L3, [R1, R2, R3]>;
// ... until 10 elements
values: Array<Either<L, R>>
- Array of Either values which will be merged into Either of Array- Returns
Either<L, Array<R>>
which will containRight<Array<R>>
if all of array elements wasRight<R>
otherwiseLeft<L>
.
Example:
const v1 = right<TypeError, number>(2); // Either<TypeError, number>.Right
const v2 = right<ReferenceError, string>("test"); // Either<ReferenceError, string>.Right
const v3 = left<Error, boolean>(new Error()); // Either<Error, boolean>.Left
merge([v1, v2]); // Either<TypeError | ReferenceError, [number, string]>.Right
merge([v1, v2, v3]); // Either<TypeError | ReferenceError | Error, [number, string, boolean]>.Left
mergeInMany
function mergeInMany<L1, R1>(values: [Either<L1, R1>]): Either<Array<L1>, [R1]>;
function mergeInMany<L1, R1, L2, R2>(values: [Either<L1, R1>, Either<L2, R2>]): Either<Array<L1 | L2>, [R1, R2]>;
function mergeInMany<L1, R1, L2, R2, L3, R3>(
values: [Either<L1, R1>, Either<L2, R2>, Either<L3, R3>]
): Either<Array<L1 | L2 | L3>, [R1, R2, R3]>;
// ... until 10 elements
values: Array<Either<L, R>>
- Array of Either values which will be merged into Either of Array- Returns
Either<Array<L>, Array<R>>
which will containRight<Array<R>>
if all of array elements wasRight<R>
otherwise array of all caughtLeft<L>
values.
Example:
const v1 = right<TypeError, number>(2); // Either<TypeError, number>.Right
const v2 = right<ReferenceError, string>("test"); // Either<ReferenceError, string>.Right
const v3 = left<Error, boolean>(new Error()); // Either<Error, boolean>.Left
merge([v1, v2]); // Either<Array<TypeError | ReferenceError>, [number, string]>.Right
merge([v1, v2, v3]); // Either<Array<TypeError | ReferenceError | Error>, [number, string, boolean]>.Left
left
function left<L, R>(value: L): Either<L, R>;
- Returns
Either
withLeft
state which contain value withL
type. Example:
const v1 = left(new Error()); // Either<Error, never>.Left
const v2 = left<Error, number>(new Error()); // Either<Error, number>.Left
right
function right<L, R>(value: R): Either<L, R>;
- Returns
Either
withRight
state which contain value withR
type. Example:
const v1 = right(2); // Either<never, number>.Right
const v2 = right<Error, number>(2); // Either<Error, number>.Right
from
The same as right
Return only Right
typed value.
function from<R>(value: R): Either<never, R>;
- Returns
Either
withRight
state which contain value withR
type. Example:
from(2); // Either<never, number>.Right
fromTry
Returns Right
with function result or Left
if function execution throws an error.
function fromTry<L, R>(fn: () => R): Either<L, R>;
fromTry(() => 2); // Either<never, number>.Right
fromTry(() => {
throw new Error("test");
}); // Either<Error, never>.Left
fromPromise
Returns Right
with the promise value if the provided promise fulfilled or Left
with the error value if the provided promise rejected.
function fromPromise<L, R>(promise: Promise<R>): Promise<Either<L, R>>;
fromPromise(Promise.resolve(2)); // Either<never, number>.Right
fromPromise(Promise.reject(new Error("test"))); // Either<Error, never>.Left
isEither
function isEither<L, R>(value: unknown | Either<L, R>): value is Either<L, R>;
- Returns
boolean
if givenvalue
is instance of Either constructor. Example:
const value: unknown = 2;
if (isEither(value)) {
// ... value is Either<unknown, unknown> at this block
}
Either#isLeft
function isLeft(): boolean;
- Returns
true
if state ofEither
isLeft
otherwisefalse
Example:
const v1 = right(2);
const v2 = left(2);
v1.isLeft(); // false
v2.isLeft(); // true
Either#isRight
function isRight(): boolean;
- Returns
true
if state ofEither
isRight
otherwisefalse
Example:
const v1 = right(2);
const v2 = left(2);
v1.isRight(); // true
v2.isRight(); // false
Either#or
function or<L, R>(x: Either<L, R>): Either<L, R>;
- Returns
Either<L, R>
. If state ofthis
isRight
thenthis
will be returned otherwisex
argument will be returned Example:
const v1 = right<string, number>(2);
const v2 = left<string, number>("Error 1");
const v3 = left<string, number>("Error 2");
const v4 = right<string, number>(3);
v1.or(v2); // v1 will be returned
v2.or(v1); // v1 will be returned
v2.or(v3); // v3 will be returned
v1.or(v4); // v1 will be returned
v2.or(v3).or(v1); // v1 will be returned
v2.or(v1).or(v3); // v1 will be returned
v1.or(v2).or(v3); // v1 will be returned
Either#join
function join<L1, L2, R>(this: Either<L1, Either<L2, R>>): Either<L1 | L2, R>;
this: Either<L1, Either<L2, R>>
-Either
instance which contains otherEither
instance asRight
value.- Returns unwrapped
Either
- if currentEither
hasRight
state and innerEither
hasRight
state then returns innerEither
Right
, if innerEither
hasLeft
state then return innerEither
Left
otherwise outerEither
Left
. Example:
const v1 = right(right(2));
const v2 = right(left(new Error()));
const v3 = left<TypeError, Either<Error, number>>(new TypeError());
v1.join(); // Either.Right with value 2
v2.join(); // Either.Left with value new Error
v3.join(); // Either.Left with value new TypeError
Either#map
function map<L, R, NewR>(fn: (val: R) => NewR): Either<L, NewR>;
- Returns mapped by
fn
function value wrapped byEither
ifEither
isRight
otherwiseLeft
withL
value Example:
const v1 = right<Error, number>(2);
const v2 = left<Error, number>(new Error());
const newVal1 = v1.map(a => a.toString()); // Either<Error, string>.Right with value "2"
const newVal2 = v2.map(a => a.toString()); // Either<Error, string>.Left with value new Error()
Either#mapRight
function mapRight<L, R, NewR>(fn: (val: R) => NewR): Either<L, NewR>;
The same as Either#map
- Returns mapped by
fn
function value wrapped byEither
ifEither
isRight
otherwiseLeft
withL
value Example:
const v1 = right<Error, number>(2);
const v2 = left<Error, number>(new Error());
const newVal1 = v1.map(a => a.toString()); // Either<Error, string>.Right with value "2"
const newVal2 = v2.map(a => a.toString()); // Either<Error, string>.Left with value new Error()
Either#mapLeft
function mapLeft<L, R, NewL>(fn: (val: L) => NewL): Either<NewL, R>;
- Returns mapped by
fn
function value wrapped byEither
ifEither
isLeft
otherwiseRight
withR
value Example:
const v1 = right<Error, number>(2);
const v2 = left<Error, number>(new Error());
const newVal1 = v1.mapLeft(a => a.toString()); // Either<string, number>.Right with value 2
const newVal2 = v2.mapLeft(a => a.toString()); // Either<string, number>.Left with value "Error"
Either#asyncMap
function asyncMap<L, R, NewR>(fn: (val: R) => Promise<NewR>): Promise<Either<L, NewR>>;
- Returns
Promise
with mapped byfn
function value wrapped byEither
ifEither
isRight
otherwiseLeft
with valueL
Example:
const v1 = right<Error, number>(2);
const v2 = left<Error, number>(new Error());
// Promise<Either<Error, string>.Right> with value "2"
const newVal1 = v1.asyncMap(a => Promise.resolve(a.toString()));
// Promise<Either<Error, string>.Left> with value new Error()
const newVal2 = v2.asyncMap(a => Promise.resolve(a.toString()));
Either#apply
function apply<A, B>(this: Either<L, (a: A) => B>, arg: Either<L, A>): Either<L, B>;
function apply<A, B>(this: Either<L, A>, fn: Either<L, (a: A) => B>): Either<L, B>;
this | fn
- function wrapped by Either, which should be applied to valuearg
arg | this
- value which should be applied tofn
- Returns mapped by
fn
function value wrapped byEither
ifEither
isRight
otherwiseLeft
withL
value Example:
const v1 = right<Error, number>(2);
const v2 = left<Error, number>(new Error());
const fn1 = right<Error, (a: number) => number>((a: number) => a * 2);
const fn2 = left<Error, (a: number) => number>(new Error());
const newVal1 = fn1.apply(v1); // Either<Error, number>.Right with value 4
const newVal2 = fn1.apply(v2); // Either<Error, number>.Left with value new Error()
const newVal3 = fn2.apply(v1); // Either<Error, number>.Left with value new Error()
const newVal4 = fn2.apply(v2); // Either<Error, number>.Left with value new Error()
Either#asyncApply
Async variant of Either#apply
function asyncApply<A, B>(this: Either<L, (a: A) => Promise<B>>, arg: Either<L, Promise<A> | A>): Promise<Either<L, B>>;
function asyncApply<A, B>(this: Either<L, Promise<A> | A>, fn: Either<L, (a: A) => Promise<B>>): Promise<Either<L, B>>;
function asyncApply<A, B>(
this: Either<L, Promise<A> | A> | Either<L, (a: A) => Promise<B>>,
argOrFn: Either<L, Promise<A> | A> | Either<L, (a: A) => Promise<B>>
): Promise<Either<L, B>>;
this | fn
- function wrapped by Either, which should be applied to valuearg
arg | this
- value which should be applied tofn
- Returns
Promise
with mapped byfn
function value wrapped byEither
ifEither
isRight
otherwiseLeft
withL
value Example:
const v1 = right<Error, number>(2);
const v2 = left<Error, number>(new Error());
const fn1 = right<Error, (a: number) => Promise<number>>((a: number) => Promise.resolve(a * 2));
const fn2 = left<Error, (a: number) => Promise<number>>(new Error());
const newVal1 = fn1.apply(v1); // Promise<Either<Error, number>.Right> with value 4
const newVal2 = fn1.apply(v2); // Promise<Either<Error, number>.Left> with value new Error()
const newVal3 = fn2.apply(v1); // Promise<Either<Error, number>.Left> with value new Error()
const newVal4 = fn2.apply(v2); // Promise<Either<Error, number>.Left> with value new Error()
Either#chain
function chain<L, R, NewL, NewR>(fn: (val: R) => Either<NewL, NewR>): Either<L | newL, NewR>;
- Returns mapped by
fn
function value wrapped byEither
ifEither
isRight
and returned byfn
value isRight
too otherwiseLeft
Example:
const v1 = right<Error, number>(2);
const v2 = left<Error, number>(new Error());
// Either<Error | TypeError, string>.Right with value "2"
const newVal1 = v1.chain(a => right<TypeError, string>(a.toString()));
// Either<Error | TypeError, string>.Left with value new TypeError()
const newVal2 = v1.chain(a => left<TypeError, string>(new TypeError()));
// Either<Error | TypeError, string>.Left with value new Error()
const newVal3 = v2.chain(a => right<TypeError, string>(a.toString()));
// Either<Error | TypeError, string>.Left with value new Error()
const newVal4 = v2.chain(a => left<TypeError, string>(new TypeError()));
Either#asyncChain
function chain<L, R, NewL, NewR>(fn: (val: R) => Promise<Either<NewL, NewR>>): Promise<Either<L | newL, NewR>>;
- Returns
Promise
with mapped byfn
function value wrapped byEither
ifEither
isRight
and returned byfn
value isRight
too otherwiseLeft
Example:
const v1 = right<Error, number>(2);
const v2 = left<Error, number>(new Error());
// Promise<Either<Error | TypeError, string>.Right> with value "2"
const newVal1 = v1.asyncChain(a => right<TypeError, string>(a.toString()));
// Promise<Either<Error | TypeError, string>.Left> with value new TypeError()
const newVal2 = v1.asyncChain(a => left<TypeError, string>(new TypeError()));
// Promise<Either<Error | TypeError, string>.Left> with value new Error()
const newVal3 = v2.asyncChain(a => right<TypeError, string>(a.toString()));
// Promise<Either<Error | TypeError, string>.Left> with value new Error()
const newVal4 = v2.chain(a => left<TypeError, string>(new TypeError()));
Either#fold
function fold<C>(mapLeft: (value: L) => C, mapRight: (value: R) => C): C;
- Returns values mapped by
mapRight
ifEither
isRight
, otherwise value mapped bymapLeft
Example:
const v1 = right<Error, number>(2);
const v2 = left<Error, number>(new Error());
// 4
const newVal1 = v1.fold(() => 'fail', value => value * 2);
// "fail"
const newVal2 = v2.fold(() => 'fail', value => value * 2);
Helpers
// Value from Either instance
const { value } = right<Error, number>(2); // number | Error
const { value } = right(2); // number
const { value } = left<Error, number>(new Error()); // number | Error
const { value } = left(new Error()); // Error
right(2).unwrap(); // number
left(new TypeError()).unwrap(); // throws error
right(2).unwrap(); // number
left(new TypeError()).unwrap(x => x); // throws TypeError provied in arguments
left(2).unwrapOr(3) // returns 3
rigth(2).unwrapOr(3) // returns 2
left(2).unwrapOrElse(num => num * 2) // returns 4
right(2).unwrapOrElse(num => num * 2) // returns 2
License
MIT (c) Artem Kobzar see LICENSE file.