UNPKG

@rustable/enum

Version:

Rust-inspired pattern matching and type-safe error handling for TypeScript. Includes Option<T> for null-safety and Result<T, E> for error handling, with comprehensive pattern matching support

253 lines (250 loc) 6.61 kB
import { Enum } from './enum.mjs'; import { Some, None } from './option.mjs'; "use strict"; class Result extends Enum { static Ok(value) { return new Result("Ok", value); } static Err(error) { return new Result("Err", error); } /** * Checks if the Result is Ok * @returns True if Ok, false if Err * * @example * ```typescript * const result = Ok(5); * if (result.isOk()) { * console.log("Operation succeeded"); * } * ``` */ isOk() { return this.is("Ok"); } /** * Checks if the Result is Err * @returns True if Err, false if Ok * * @example * ```typescript * const result = Err(new Error("Failed")); * if (result.isErr()) { * console.log("Operation failed"); * } * ``` */ isErr() { return this.is("Err"); } /** * Converts to Option<T>, Some(t) if Ok(t), None if Err * @returns Option<T> representation of the Result */ ok() { return this.isOk() ? Some(super.unwrap()) : None; } /** * Converts to Option<E>, Some(e) if Err(e), None if Ok * @returns Option<E> representation of the Result */ err() { return this.isErr() ? Some(super.unwrap()) : None; } /** * Returns the Ok value or throws if Err * @throws Error if the Result is Err * @returns T Ok value */ unwrap() { if (this.isOk()) { return super.unwrap(); } throw super.unwrap(); } /** * Returns the Ok value or the provided default * @param def Default value to return if Err * @returns T Ok value or default */ unwrapOr(def) { return this.isOk() ? super.unwrap() : def; } /** * Returns the Ok value or computes it from the error * @param fn Function to compute the Ok value from the error * @returns T Ok value or computed value */ unwrapOrElse(fn) { return this.isOk() ? super.unwrap() : fn(super.unwrap()); } /** * Returns the Ok value or throws the error if Err * @throws Error if the Result is Err * @returns T Ok value */ unwrapOrThrow() { if (this.isOk()) return super.unwrap(); throw super.unwrap(); } /** * Returns the Err value or throws if Ok * @throws Error if the Result is Ok * @returns E Err value */ unwrapErr() { if (this.isErr()) return super.unwrap(); throw new ReferenceError("Cannot unwrap Err value of Result.Ok"); } /** * Pattern matches on the Result * @param fn Match handlers for Ok and Err values * @returns Result of matching the Result */ match(fn) { return super.match(fn); } /** * Maps the Ok value using the provided function * @param fn Function to map the Ok value * @returns Result<U, E> mapped Result */ map(fn) { return this.isOk() ? Result.Ok(fn(super.unwrap())) : Result.Err(super.unwrap()); } /** * Maps the Ok value using the provided function, or returns the default value if Err * @param defaultValue Default value to return if Err * @param fn Function to map the Ok value * @returns U mapped value or default */ mapOr(defaultValue, fn) { return this.isOk() ? fn(super.unwrap()) : defaultValue; } /** * Maps the Err value using the provided function * @param fn Function to map the Err value * @returns Result<T, U> mapped Result */ mapErr(fn) { return this.isOk() ? Result.Ok(super.unwrap()) : Result.Err(fn(super.unwrap())); } /** * Throws an error if the Result is Err * @param msg Error message to include in the error * @returns T Ok value */ expect(msg) { if (this.isOk()) return super.unwrap(); throw new Error(`${msg}: ${super.unwrap()}`); } /** * Chained Result-returning functions * @param res Result to chain * @returns Result<U, E> chained Result */ and(res) { return this.isOk() ? res : Result.Err(super.unwrap()); } /** * Chain Result-returning functions * @param op Function to chain * @returns Result<U, E> chained Result */ andThen(op) { return this.isOk() ? op(super.unwrap()) : Result.Err(super.unwrap()); } /** * Chained Result-returning functions * @param res Result to chain * @returns Result<T, F> chained Result */ or(res) { return this.isOk() ? Result.Ok(super.unwrap()) : res; } /** * Returns this Result if Ok, or computes a new Result if Err * @param fn Function to compute a new Result if Err * @returns Result<T, E> or Result<U, E> computed Result */ orElse(fn) { return this.isOk() ? Result.Ok(super.unwrap()) : fn(super.unwrap()); } /** * Wraps a Promise into a Result, converting successful resolution to Ok and rejection to Err * @template T Type of the success value * @template E Type of the error value, must extend Error * @param promise Promise to wrap * @returns Promise<Result<T, E>> A promise that resolves to a Result * * @example * ```typescript * // Wrap a promise that might fail * const result = await Result.fromPromise<string, Error>( * fetch('https://api.example.com/data') * .then(res => res.text()) * ); * * // Handle the result * if (result.isOk()) { * console.log('Got data:', result.unwrap()); * } else { * console.error('Failed:', result.unwrapErr().message); * } * ``` */ static async fromAsync(promise) { try { const value = await promise; return Result.Ok(value); } catch (error) { return Result.Err(error); } } /** * Wraps a function in a Result, converting successful execution to Ok and thrown errors to Err * @template T Type of the return value * @template E Type of the error value, must extend Error * @template Args Type of the function arguments * @param fn Function to wrap * @returns A function that returns Result<T, E> * * @example * ```typescript * const parseJSON = Result.fromFn<any, Error, [string]>(JSON.parse); * * // Success case * const result1 = parseJSON('{"key": "value"}'); * if (result1.isOk()) { * console.log('Parsed:', result1.unwrap()); * } * * // Error case * const result2 = parseJSON('invalid json'); * if (result2.isErr()) { * console.error('Parse failed:', result2.unwrapErr().message); * } * ``` */ static fromFn(fn) { return (...args) => { try { const value = fn(...args); return Result.Ok(value); } catch (error) { return Result.Err(error); } }; } } function Ok(val) { return Result.Ok(val); } function Err(err) { return Result.Err(err); } export { Err, Ok, Result };