@sweet-monads/either
v3.3.1
Published
Either monad
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
chainmergemergeInOnemergeInManyleftrightfromfromTryfromPromiseisEitherEither#isLeftEither#isRightEither#orEither#joinEither#mapEither#mapRightEither#mapLeftEither#asyncMapEither#applyEither#asyncApplyEither#chainEither#asyncChainEither#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 promisedEitherwith new error or mapped byfnvalue (could be used insidePromise#thenfunction).
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 elementsvalues: 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]>.LeftmergeInOne
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 elementsvalues: 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]>.LeftmergeInMany
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 elementsvalues: 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]>.Leftleft
function left<L, R>(value: L): Either<L, R>;- Returns
EitherwithLeftstate which contain value withLtype. Example:
const v1 = left(new Error()); // Either<Error, never>.Left
const v2 = left<Error, number>(new Error()); // Either<Error, number>.Leftright
function right<L, R>(value: R): Either<L, R>;- Returns
EitherwithRightstate which contain value withRtype. Example:
const v1 = right(2); // Either<never, number>.Right
const v2 = right<Error, number>(2); // Either<Error, number>.Rightfrom
The same as right
Return only Right typed value.
function from<R>(value: R): Either<never, R>;- Returns
EitherwithRightstate which contain value withRtype. Example:
from(2); // Either<never, number>.RightfromTry
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>.LeftfromPromise
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>.LeftisEither
function isEither<L, R>(value: unknown | Either<L, R>): value is Either<L, R>;- Returns
booleanif givenvalueis 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
trueif state ofEitherisLeftotherwisefalseExample:
const v1 = right(2);
const v2 = left(2);
v1.isLeft(); // false
v2.isLeft(); // trueEither#isRight
function isRight(): boolean;- Returns
trueif state ofEitherisRightotherwisefalseExample:
const v1 = right(2);
const v2 = left(2);
v1.isRight(); // true
v2.isRight(); // falseEither#or
function or<L, R>(x: Either<L, R>): Either<L, R>;- Returns
Either<L, R>. If state ofthisisRightthenthiswill be returned otherwisexargument 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 returnedEither#join
function join<L1, L2, R>(this: Either<L1, Either<L2, R>>): Either<L1 | L2, R>;this: Either<L1, Either<L2, R>>-Eitherinstance which contains otherEitherinstance asRightvalue.- Returns unwrapped
Either- if currentEitherhasRightstate and innerEitherhasRightstate then returns innerEitherRight, if innerEitherhasLeftstate then return innerEitherLeftotherwise outerEitherLeft. 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 TypeErrorEither#map
function map<L, R, NewR>(fn: (val: R) => NewR): Either<L, NewR>;- Returns mapped by
fnfunction value wrapped byEitherifEitherisRightotherwiseLeftwithLvalue 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
fnfunction value wrapped byEitherifEitherisRightotherwiseLeftwithLvalue 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
fnfunction value wrapped byEitherifEitherisLeftotherwiseRightwithRvalue 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
Promisewith mapped byfnfunction value wrapped byEitherifEitherisRightotherwiseLeftwith valueLExample:
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 valueargarg | this- value which should be applied tofn- Returns mapped by
fnfunction value wrapped byEitherifEitherisRightotherwiseLeftwithLvalue 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 valueargarg | this- value which should be applied tofn- Returns
Promisewith mapped byfnfunction value wrapped byEitherifEitherisRightotherwiseLeftwithLvalue 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
fnfunction value wrapped byEitherifEitherisRightand returned byfnvalue isRighttoo otherwiseLeftExample:
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
Promisewith mapped byfnfunction value wrapped byEitherifEitherisRightand returned byfnvalue isRighttoo otherwiseLeftExample:
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
mapRightifEitherisRight, otherwise value mapped bymapLeftExample:
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()); // Errorright(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 2License
MIT (c) Artem Kobzar see LICENSE file.
