/** * The [[Either]] type represents an alternative between two value types. * A "left" value which is also conceptually tied to a failure, * or a "right" value which is conceptually tied to success. * * The code is organized through the class [[Left]], the class [[Right]], * and the type alias [[Either]] (Left or Right). * * Finally, "static" functions on Option are arranged in the class * [[EitherStatic]] and are accessed through the global constant Either. * * Examples: * * Either.right(5); * Either.left(2); * Either.right(5).map(x => x*2); * * Left has the extra [[Left.getLeft]] method that [[Right]] doesn't have. * Right has the extra [[Right.get]] method that [[Left]] doesn't have. */ import { Value } from "./Value"; import { Option } from "./Option"; import { LinkedList } from "./LinkedList"; import { Vector } from "./Vector"; import { WithEquality } from "./Comparison"; /** * Holds the "static methods" for [[Either]] */ export declare class EitherStatic { /** * Constructs an Either containing a left value which you give. */ left(val: L): Either; /** * Constructs an Either containing a right value which you give. */ right(val: R): Either; /** * Curried type guard for Either * Sometimes needed also due to https://github.com/Microsoft/TypeScript/issues/20218 * * Vector.of(Either.right(2), Either.left(1)) * .filter(Either.isLeft) * .map(o => o.getLeft()) * => Vector.of(1) */ isLeft(e: Either): e is Left; /** * Curried type guard for Either * Sometimes needed also due to https://github.com/Microsoft/TypeScript/issues/20218 * * Vector.of(Either.right(2), Either.left(1)) * .filter(Either.isRight) * .map(o => o.get()) * => Vector.of(2) */ isRight(e: Either): e is Right; /** * Turns a list of eithers in an either containing a list of items. * Useful in many contexts. * * Either.sequence(Vector.of( * Either.right(1), * Either.right(2))); * => Either.right(Vector.of(1,2)) * * But if a single element is Left, everything is discarded: * * Either.sequence(Vector.of( * Either.right(1), * Either.left(2), * Either.left(3))); * => Either.left(2) * * Also see [[EitherStatic.traverse]] */ sequence(elts: Iterable>): Either>; /** * Takes a list, a function that can transform list elements * to eithers, then return an either containing a list of * the transformed elements. * * const getUserById: (x:number)=>Either = x => x > 0 ? * Either.right("user" + x.toString()) : Either.left("invalid id!"); * Either.traverse([4, 3, 2], getUserById); * => Either.right(Vector.of("user4", "user3", "user2")) * * But if a single element results in Left, everything is discarded: * * const getUserById: (x:number)=>Either = x => x > 0 ? * Either.right("user" + x.toString()) : Either.left("invalid id!"); * Either.traverse([4, -3, 2], getUserById); * => Either.left("invalid id!") * * Also see [[EitherStatic.sequence]] */ traverse(elts: Iterable, fn: (x: T) => Either): Either>; /** * Turns a list of eithers in an either containing a list of items. * Compared to [[EitherStatic.sequence]], sequenceAcc 'accumulates' * the errors, instead of short-circuiting on the first error. * * Either.sequenceAcc(Vector.of( * Either.right(1), * Either.right(2))); * => Either.right(Vector.of(1,2)) * * But if a single element is Left, you get all the lefts: * * Either.sequenceAcc(Vector.of( * Either.right(1), * Either.left(2), * Either.left(3))); * => Either.left(Vector.of(2,3)) */ sequenceAcc(elts: Iterable>): Either, Vector>; /** * Applicative lifting for Either. * Takes a function which operates on basic values, and turns it * in a function that operates on eithers of these values ('lifts' * the function). The 2 is because it works on functions taking two * parameters. * * const lifted = Either.liftA2( * (x:number,y:number) => x+y, {} as string); * lifted( * Either.right(5), * Either.right(6)); * => Either.right(11) * * const lifted = Either.liftA2( * (x:number,y:number) => x+y, {} as string); * lifted( * Either.right(5), * Either.left("bad")); * => Either.left("bad") * * @param R1 the first right type * @param R2 the second right type * @param L the left type * @param V the new right type as returned by the combining function. */ liftA2(fn: (v1: R1, v2: R2) => V, leftWitness?: L): (p1: Either, p2: Either) => Either; /** * Applicative lifting for Either. 'p' stands for 'properties'. * * Takes a function which operates on a simple JS object, and turns it * in a function that operates on the same JS object type except which each field * wrapped in an Either ('lifts' the function). * It's an alternative to [[EitherStatic.liftA2]] when the number of parameters * is not two. * * const fn = (x:{a:number,b:number,c:number}) => x.a+x.b+x.c; * const lifted = Either.liftAp(fn, {} as number); * lifted({ * a: Either.right(5), * b: Either.right(6), * c: Either.right(3)}); * => Either.right(14) * * const lifted = Either.liftAp( * x => x.a+x.b); * lifted({ * a: Either.right(5), * b: Either.left(2)}); * => Either.left(2) * * @param L the left type * @param A the object property type specifying the parameters for your function * @param B the type returned by your function, returned wrapped in an either by liftAp. */ liftAp(fn: (x: A) => B, leftWitness?: L): (x: { [K in keyof A]: Either; }) => Either; /** * Applicative lifting for Either. 'p' stands for 'properties'. * Compared to [[EitherStatic.liftAp]], liftApAcc 'accumulates' * the errors, instead of short-circuiting on the first error. * * Takes a function which operates on a simple JS object, and turns it * in a function that operates on the same JS object type except which each field * wrapped in an Either ('lifts' the function). * It's an alternative to [[EitherStatic.liftA2]] when the number of parameters * is not two. * * const fn = (x:{a:number,b:number,c:number}) => x.a+x.b+x.c; * const lifted = Either.liftApAcc(fn, {} as number); * lifted({ * a: Either.right(5), * b: Either.right(6), * c:Either.right(3)}); * => Either.right(14) * * const fn = (x:{a:number,b:number,c:number}) => x.a+x.b+x.c; * const lifted = Either.liftApAcc(fn, {} as number); * lifted({ * a: Either.right(5), * b: Either.left(2), * c: Either.left(6)}); * => Either.left(Vector.of(2, 6)) * * @param L the left type * @param A the object property type specifying the parameters for your function * @param B the type returned by your function, returned wrapped in an either by liftAp. */ liftApAcc(fn: (x: A) => B, leftWitness?: L): (x: { [K in keyof A]: Either; }) => Either, B>; /** * Take a partial function (may return undefined or throw), * and lift it to return an [[Either]] instead. * * Note that unlike the [[OptionStatic.lift]] version, if * the function returns undefined, the Either.lift version will throw * (the Option.lift version returns None()): if you want to do * pure side-effects which may throw, you're better off just using * javascript try blocks. * * When using typescript, to help the compiler infer the left type, * you can either pass a second parameter like `{} as `, or * call with `lift(...)`. * * const add = Either.lift((x:number,y:number) => x+y, {} as string); * add(1,2); * => Either.right(3) * * const undef = Either.lift((x:number,y:number,z:number) => undefined); * undef(1,2,3); * => throws * * const throws = Either.lift(() => {throw "x"}); * throws(); * => Either.left("x") */ lift(fn: (...args: T) => U, witness?: L): (...args: T) => Either; /** * Take a no-parameter partial function (may return undefined or throw), * call it, and return an [[Either]] instead. * * Note that unlike the [[OptionStatic.try_]] version, if * the function returns undefined, this function will throw * (the Option.try_ version returns None()): if you want to do * pure side-effects which may throw, you're better off just using * javascript try blocks. * * When using typescript, to help the compiler infer the left type, * you can either pass a second parameter like `{} as `, or * call with `try_(...)`. * * Either.try_(Math.random, {} as string); * => Either.right(0.49884723907769635) * * Either.try_(() => undefined); * => throws * * Either.try_(() => {throw "x"}); * => Either.left("x") * * Also see [[Function0.liftEither]], [[OptionStatic.try_]], * [[OptionStatic.tryNullable]] */ try_(fn: () => T, witness?: L): Either; } /** * The Either constant allows to call the either "static" methods */ export declare const Either: EitherStatic; /** * Either represents an alternative between two value types. * A "left" value which is also conceptually tied to a failure, * or a "right" value which is conceptually tied to success. * "static methods" available through [[EitherStatic]] */ export declare type Either = Left | Right; /** * Represents an [[Either]] containing a left value, * conceptually tied to a failure. * "static methods" available through [[EitherStatic]] * @param L the "left" item type 'failure' * @param R the "right" item type 'success' */ export declare class Left implements Value { private value; constructor(value: L); /** * @hidden */ readonly className: "Left"; /** * Returns true since this is a Left */ isLeft(): this is Left; /** * Returns false since this is a Left */ isRight(): this is Right; /** * Returns true if this is either is a right and contains the value you give. */ contains(val: R & WithEquality): boolean; /** * If this either is a right, applies the function you give * to its contents and build a new right either, otherwise return this. */ map(fn: (x: R) => U): Either; /** * If this either is a right, call the function you give with * the contents, and return what the function returns, else * returns this. * This is the monadic bind. */ flatMap(fn: (x: R) => Either): Either; /** * If this either is a left, call the function you give with * the left value and return a new either left with the result * of the function, else return this. */ mapLeft(fn: (x: L) => U): Either; /** * Map the either: you give a function to apply to the value, * a function in case it's a left, a function in case it's a right. */ bimap(fnL: (x: L) => S, fnR: (x: R) => T): Either; /** * "filter" the either. If it was a Left, it stays a Left. * If it was a Right and the predicate you pass returns * true for its value, return the either unchanged. * But if it was a left and the predicate returns false, * return a Left with the value returned by the function * passed as second parameter. * * Either.right(-3) * .filter(x => x >= 0, v => "got negative value: " + v); * => Either.left("got negative value: -3") */ filter(p: (x: R) => boolean, filterVal: (x: R) => L): Either; /** * Combines two eithers. If this either is a right, returns it. * If it's a left, returns the other one. */ orElse(other: Either): Either; /** * Execute a side-effecting function if the either * is a right; returns the either. */ ifRight(fn: (x: R) => void): Either; /** * Execute a side-effecting function if the either * is a left; returns the either. */ ifLeft(fn: (x: L) => void): Either; /** * Handle both branches of the either and return a value * (can also be used for side-effects). * This is the catamorphism for either. * * Either.right(5).match({ * Left: x => "left " + x, * Right: x => "right " + x * }); * => "right 5" */ match(cases: { Left: (v: L) => U; Right: (v: R) => U; }): U; /** * If this either is a right, return its value, else throw * an exception. * You can optionally pass a message that'll be used as the * exception message, or an Error object. */ getOrThrow(errorInfo?: Error | string): R; /** * If this either is a right, return its value, else return * the value you give. */ getOrElse(other: R): R; /** * Get the value contained in this left. * NOTE: we know it's there, since this method * belongs to Left, not Either. */ getLeft(): L; /** * If this either is a left, return its value, else throw * an exception. * You can optionally pass a message that'll be used as the * exception message. */ getLeftOrThrow(message?: string): L; /** * If this either is a left, return its value, else return * the value you give. */ getLeftOrElse(other: L): L; /** * Convert this either to an option, conceptually dropping * the left (failing) value. */ toOption(): Option; /** * Convert to a vector. If it's a left, it's the empty * vector, if it's a right, it's a one-element vector with * the contents of the either. */ toVector(): Vector; /** * Convert to a list. If it's a left, it's the empty * list, if it's a right, it's a one-element list with * the contents of the either. */ toLinkedList(): LinkedList; /** * Transform this value to another value type. * Enables fluent-style programming by chaining calls. */ transform(converter: (x: Either) => U): U; hasTrueEquality(): boolean; /** * Get a number for that object. Two different values * may get the same number, but one value must always get * the same number. The formula can impact performance. */ hashCode(): number; /** * Two objects are equal if they represent the same value, * regardless of whether they are the same object physically * in memory. */ equals(other: Either): boolean; /** * Get a human-friendly string representation of that value. */ toString(): string; /** * Used by the node REPL to display values. */ inspect(): string; } /** * Represents an [[Either]] containing a success value, * conceptually tied to a success. * "static methods" available through [[EitherStatic]] * @param L the "left" item type 'failure' * @param R the "right" item type 'success' */ export declare class Right implements Value { private value; constructor(value: R); /** * @hidden */ readonly className: "Right"; /** * Returns false since this is a Right */ isLeft(): this is Left; /** * Returns true since this is a Right */ isRight(): this is Right; /** * Returns true if this is either is a right and contains the value you give. */ contains(val: R & WithEquality): boolean; /** * If this either is a right, applies the function you give * to its contents and build a new right either, otherwise return this. */ map(fn: (x: R) => U): Either; /** * If this either is a right, call the function you give with * the contents, and return what the function returns, else * returns this. * This is the monadic bind. */ flatMap(fn: (x: R) => Either): Either; /** * If this either is a left, call the function you give with * the left value and return a new either left with the result * of the function, else return this. */ mapLeft(fn: (x: L) => U): Either; /** * Map the either: you give a function to apply to the value, * a function in case it's a left, a function in case it's a right. */ bimap(fnL: (x: L) => S, fnR: (x: R) => T): Either; /** * "filter" the either. If it was a Left, it stays a Left. * If it was a Right and the predicate you pass returns * true for its value, return the either unchanged. * But if it was a left and the predicate returns false, * return a Left with the value returned by the function * passed as second parameter. * * Either.right(-3) * .filter(x => x >= 0, v => "got negative value: " + v); * => Either.left("got negative value: -3") */ filter(p: (x: R) => boolean, filterVal: (x: R) => L): Either; /** * Combines two eithers. If this either is a right, returns it. * If it's a left, returns the other one. */ orElse(other: Either): Either; /** * Execute a side-effecting function if the either * is a right; returns the either. */ ifRight(fn: (x: R) => void): Either; /** * Execute a side-effecting function if the either * is a left; returns the either. */ ifLeft(fn: (x: L) => void): Either; /** * Handle both branches of the either and return a value * (can also be used for side-effects). * This is the catamorphism for either. * * Either.right(5).match({ * Left: x => "left " + x, * Right: x => "right " + x * }); * => "right 5" */ match(cases: { Left: (v: L) => U; Right: (v: R) => U; }): U; /** * Get the value contained in this right. * NOTE: we know it's there, since this method * belongs to Right, not Either. */ get(): R; /** * If this either is a right, return its value, else throw * an exception. * You can optionally pass a message that'll be used as the * exception message, or an Error object. */ getOrThrow(errorInfo?: Error | string): R; /** * If this either is a right, return its value, else return * the value you give. */ getOrElse(other: R): R; /** * If this either is a left, return its value, else throw * an exception. * You can optionally pass a message that'll be used as the * exception message. */ getLeftOrThrow(message?: string): L; /** * If this either is a left, return its value, else return * the value you give. */ getLeftOrElse(other: L): L; /** * Convert this either to an option, conceptually dropping * the left (failing) value. */ toOption(): Option; /** * Convert to a vector. If it's a left, it's the empty * vector, if it's a right, it's a one-element vector with * the contents of the either. */ toVector(): Vector; /** * Convert to a list. If it's a left, it's the empty * list, if it's a right, it's a one-element list with * the contents of the either. */ toLinkedList(): LinkedList; /** * Transform this value to another value type. * Enables fluent-style programming by chaining calls. */ transform(converter: (x: Either) => U): U; hasTrueEquality(): boolean; /** * Get a number for that object. Two different values * may get the same number, but one value must always get * the same number. The formula can impact performance. */ hashCode(): number; /** * Two objects are equal if they represent the same value, * regardless of whether they are the same object physically * in memory. */ equals(other: Either): boolean; /** * Get a human-friendly string representation of that value. */ toString(): string; /** * Used by the node REPL to display values. */ inspect(): string; }