UNPKG

@thames/monads

Version:

Option, Result, and Either types for JavaScript - Inspired by Rust

273 lines (272 loc) 9.11 kB
import { NoneOption, Option, SomeOption } from '../option/option'; /** * Type representing any value except 'undefined'. * This is useful for ensuring a value can be null but not undefined, especially with strict null checks. */ type NonUndefined = {} | null; /** * Enum-like object for representing the state of an Either: Left or Right. */ export declare const EitherType: { Left: symbol; Right: symbol; }; /** * Interface for handling match operations on an Either. * Enables executing different logic based on the Either being Left or Right. */ interface Match<L, R, U> { left: (val: L) => U; right: (val: R) => U; } /** * The Either interface, representing a value that is either Left (usually an error or alternate value) * or Right (typically a success value). It is a powerful way to handle operations that can result in two * distinctly different types of outcomes. */ export interface Either<L extends NonUndefined, R extends NonUndefined> { /** * A symbol indicating whether the Either is Left or Right. Primarily for internal use. */ type: symbol; /** * Checks if the Either is a Left value. * * @returns true if the Either is Left, otherwise false. * * #### Example * * ```ts * console.log(Left('error').isLeft()); // true * console.log(Right(42).isLeft()); // false * ``` */ isLeft(): this is LeftEither<L, R>; /** * Checks if the Either is a Right value. * * @returns true if the Either is Right, otherwise false. * * #### Example * * ```ts * console.log(Right(42).isRight()); // true * console.log(Left('error').isRight()); // false * ``` */ isRight(): this is RightEither<L, R>; /** * Converts the Either to an Option of its Left value. * * @returns An Option containing the Left value if present, otherwise None. * * #### Examples * * ```ts * const leftOption = Left('error').left(); // Some('error') * const rightOption = Right(42).left(); // None * ``` */ left(): Option<L>; /** * Converts the Either to an Option of its Right value. * * @returns An Option containing the Right value if present, otherwise None. * * #### Examples * * ```ts * const leftOption = Left('error').right(); // None * const rightOption = Right(42).right(); // Some(42) * ``` */ right(): Option<R>; /** * Unwraps the Either, yielding the contained value. * * Throws an error if the Either is not the expected type (Left or Right). * * @returns The contained value. * @throws Error if the operation is invalid. */ unwrap(): L | R; /** * Unwraps the Either, yielding the Left value if present. * * Throws an error if the Either is a Right. * * @returns The Left value. * @throws Error if the Either is Right. * * #### Example * * ```ts * console.log(Left('error').unwrapLeft()); // 'error' * ``` */ unwrapLeft(): L | never; /** * Unwraps the Either, yielding the Right value if present. * * Throws an error if the Either is a Left. * * @returns The Right value. * @throws Error if the Either is Left. * * #### Example * * ```ts * console.log(Right(42).unwrapRight()); // 42 * ``` */ unwrapRight(): R | never; /** * Returns the Left value if present, otherwise returns the provided default value. * * @param other The default value to return if the Either is Right. * @returns The Left value or the default. * * #### Example * * ```ts * console.log(Left('error').unwrapLeftOr('default')); // 'error' * console.log(Right(42).unwrapLeftOr('default')); // 'default' * ``` */ unwrapLeftOr(other: L): L; /** * Returns the Right value if present, otherwise returns the provided default value. * * @param other The default value to return if the Either is Left. * @returns The Right value or the default. * * #### Example * * ```ts * console.log(Right(42).unwrapRightOr(100)); // 42 * console.log(Left('error').unwrapRightOr(100)); // 100 * ``` */ unwrapRightOr(other: R): R; /** * Performs a match operation on the Either, allowing for branching logic based on its state. * * @param fn An object containing functions for each case: Left and Right. * @returns The result of applying the corresponding function based on the Either's state. * * #### Examples * * ```ts * const either = Left('error'); * const result = either.match({ * left: (err) => `Error: ${err}`, * right: (val) => `Success: ${val}`, * }); * console.log(result); // "Error: error" * ``` */ match<U extends NonUndefined>(fn: Match<L, R, U>): U; /** * Maps an Either by applying a function to its Left value, leaving Right untouched. * * @param fn A function to apply to the Left value. * @returns A new Either with the Left value transformed if it was Left, otherwise the original Right. * * #### Examples * * ```ts * const either = Left('error'); * const mapped = either.mapLeft((err) => `Error: ${err}`); * console.log(mapped.unwrapLeft()); // "Error: error" * ``` */ mapLeft<U extends NonUndefined>(fn: (val: L) => U): Either<U, R>; /** * Maps an Either by applying a function to its Right value, leaving Left untouched. * * @param fn A function to apply to the Right value. * @returns A new Either with the Right value transformed if it was Right, otherwise the original Left. * * #### Examples * * ```ts * const either = Right(42); * const mapped = either.mapRight((val) => val.toString()); * console.log(mapped.unwrapRight()); // "42" * ``` */ mapRight<U extends NonUndefined>(fn: (val: R) => U): Either<L, U>; /** * Transforms the Either by applying a function to its Left value if present, chaining multiple operations. * * @param fn A function that takes the Left value and returns a new Either. * @returns The Either returned by the function if the original was Left, otherwise the original Right. * * #### Examples * * ```ts * const either = Left('initial error'); * const chained = either.leftAndThen((err) => Left(`Processed ${err}`)); * console.log(chained.unwrapLeft()); // "Processed initial error" * ``` */ leftAndThen<U extends NonUndefined>(fn: (val: L) => Either<U, R>): Either<U, R>; /** * Transforms the Either by applying a function to its Right value if present, chaining multiple operations. * * @param fn A function that takes the Right value and returns a new Either. * @returns The Either returned by the function if the original was Right, otherwise the original Left. * * #### Examples * * ```ts * const either = Right(42); * const chained = either.rightAndThen((val) => Right(val.toString())); * console.log(chained.unwrapRight()); // "42" * ``` */ rightAndThen<U extends NonUndefined>(fn: (val: R) => Either<L, U>): Either<L, U>; } /** * Implementation of the Either interface for a Left value. */ export interface LeftEither<L extends NonUndefined, R extends NonUndefined> extends Either<L, R> { unwrapLeft(): L; unwrapRight(): never; left(): SomeOption<L>; right(): NoneOption<R>; mapLeft<U extends NonUndefined>(fn: (val: L) => U): LeftEither<U, R>; mapRight<U extends NonUndefined>(_fn: (val: R) => U): LeftEither<L, U>; } /** * Implementation of the Either interface for a Right value. */ export interface RightEither<L extends NonUndefined, R extends NonUndefined> extends Either<L, R> { unwrapLeft(): never; unwrapRight(): R; left(): NoneOption<L>; right(): SomeOption<R>; mapLeft<U extends NonUndefined>(_fn: (val: L) => U): RightEither<U, R>; mapRight<U extends NonUndefined>(fn: (val: R) => U): RightEither<L, U>; } /** * Factory function for creating a Left instance of Either. */ export declare function Left<L extends NonUndefined, R extends NonUndefined = never>(val: L): LeftEither<L, R>; /** * Factory function for creating a Right instance of Either. */ export declare function Right<R extends NonUndefined, L extends NonUndefined = never>(val: R): RightEither<L, R>; /** * Type guard for checking if an Either is a Left. * * @deprecated Use `Either.isLeft` instead. */ export declare function isLeft<L extends NonUndefined, R extends NonUndefined>(val: Either<L, R>): val is LeftEither<L, R>; /** * Type guard for checking if an Either is a Right. * * @deprecated Use `Either.isRight` instead. */ export declare function isRight<L extends NonUndefined, R extends NonUndefined>(val: Either<L, R>): val is RightEither<L, R>; export {};