import { isPromise } from "./is-promise.js"; /** * Result type for representing success (Ok) or failure (Err) values. * * Result is a type-safe way to handle operations that can fail, similar to Rust's * Result type. It forces explicit handling of both success and error cases without * throwing exceptions. * * @template T - The type of the success value * @template E - The type of the error (default: Error) * * @example * ```typescript * function divide(a: number, b: number): Result { * if (b === 0) { * return Result.Err('Division by zero'); * } * return Result.Ok(a / b); * } * * const result = divide(10, 2); * if (result.isOk()) { * console.log('Result:', result.unwrap()); * } else { * console.error('Error:', result.unwrap_err()); * } * ``` */ export abstract class Result { static Ok(...args: T[]): Result { return args.length >= 1 ? new ResultOK(args[0]) : new ResultOK(undefined as unknown as T); } static Err(t: E | string | Result): Result { if (typeof t === "string") { return new ResultError(new Error(t) as E); } if (Result.Is(t)) { if (t.is_ok()) { return new ResultError(new Error("Result Error is Ok") as E); } return t as Result; } return new ResultError(t); } static Is(t: unknown): t is Result { if (!t) { return false; } if (t instanceof Result) { return true; } const rt = t as Result; if ([typeof rt.is_ok, typeof rt.is_err, typeof rt.unwrap, typeof rt.unwrap_err].every((x) => x === "function")) { return true; } return false; } static AsyncOk(...args: T[]): Promise> { return Promise.resolve(Result.Ok(...args)); } static AsyncErr(t: E | string | Result): Promise> { return Promise.resolve(Result.Err(t)); } isOk(): boolean { return this.is_ok(); } isErr(): boolean { return this.is_err(); } Ok(): T { return this.unwrap(); } Err(): E { return this.unwrap_err(); } abstract is_ok(): boolean; abstract is_err(): boolean; abstract unwrap(): T; abstract unwrap_err(): E; } export class ResultOK extends Result { private _t: T; constructor(t: T) { super(); this._t = t; } is_ok(): boolean { return true; } is_err(): boolean { return false; } unwrap_err(): E { throw new Error("Result is Ok"); } unwrap(): T { return this._t; } } export class ResultError extends Result { private _error: T; constructor(t: T) { super(); this._error = t; } is_ok(): boolean { return false; } is_err(): boolean { return true; } unwrap(): never { throw new Error(`Result is Err: ${this._error}`); } unwrap_err(): T { return this._error; } } export type WithoutResult = T extends Result ? U : T; /** * Wraps a function to convert thrown exceptions into Result.Err values. * * Executes the provided function and returns Result.Ok on success or Result.Err * on thrown exceptions. Supports both synchronous and asynchronous functions. * * @template FN - Function type that returns T or Promise * @template T - The return type of the function * @param fn - Function to execute with exception handling * @returns Result for sync functions, Promise> for async functions * * @example * ```typescript * const result = exception2Result(() => { * return JSON.parse('invalid json'); * }); * // result is Result.Err with parse error * * const asyncResult = await exception2Result(async () => { * return await fetch('/api/data'); * }); * ``` */ type UnwrapResult = T extends Result ? U : T; type ReturnType = TT extends Promise ? Promise, EE>> : Result, EE>; export function exception2Result(fn: () => Promise): Promise, E>>; export function exception2Result(fn: () => T): Result, E>; export function exception2Result(fn: () => TT): ReturnType { try { const res = fn(); if (isPromise(res)) { return res .then((value) => { return Result.Is(value) ? (value as Result) : Result.Ok(value as TT); }) .catch((e) => Result.Err(e as EE)) as ReturnType; } return (Result.Is(res) ? res : Result.Ok(res)) as ReturnType; } catch (e) { return Result.Err(e as EE) as ReturnType; } }