@thames/monads
Version:
Option, Result, and Either types for JavaScript - Inspired by Rust
273 lines (272 loc) • 9.11 kB
TypeScript
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 {};