UNPKG

ts-data-forge

Version:

[![npm version](https://img.shields.io/npm/v/ts-data-forge.svg)](https://www.npmjs.com/package/ts-data-forge) [![npm downloads](https://img.shields.io/npm/dm/ts-data-forge.svg)](https://www.npmjs.com/package/ts-data-forge) [![License](https://img.shields.

611 lines 26.3 kB
import { Optional } from './optional.mjs'; /** @internal String literal tag to identify the 'Ok' variant of Result. */ declare const OkTypeTagName = "ts-data-forge::Result.ok"; /** @internal String literal tag to identify the 'Err' variant of Result. */ declare const ErrTypeTagName = "ts-data-forge::Result.err"; /** * @internal * Represents the 'Ok' variant of a Result, containing a success value. * @template S The type of the success value. */ type Ok_<S> = Readonly<{ /** * @internal * Discriminant property for the 'Ok' type. */ $$tag: typeof OkTypeTagName; /** The success value. */ value: S; }>; /** * @internal * Represents the 'Err' variant of a Result, containing an error value. * @template E The type of the error value. */ type Err_<E> = Readonly<{ /** * @internal * Discriminant property for the 'Err' type. */ $$tag: typeof ErrTypeTagName; /** The error value. */ value: E; }>; /** * Represents a value that can either be a success (`Ok`) or an error (`Err`). * @template S The type of the success value. * @template E The type of the error value. */ export type Result<S, E> = Ok_<S> | Err_<E>; /** * Namespace for the `Result` type and related functions. * Provides utilities to handle operations that can succeed or fail. */ export declare namespace Result { /** * Checks if the given value is a `Result`. * @param maybeOptional The value to check. * @returns `true` if the value is a `Result`, otherwise `false`. */ export const isResult: (maybeOptional: unknown) => maybeOptional is Result<unknown, unknown>; /** * Represents a `Result` that is a success, containing a value. * @template S The type of the success value. */ export type Ok<S> = Ok_<S>; /** * Represents a `Result` that is an error, containing an error value. * @template E The type of the error value. */ export type Err<E> = Err_<E>; /** * Base type for any `Result`, used for generic constraints. * Represents a `Result` with unknown success and error types. */ export type Base = Result<unknown, unknown>; /** * Extracts the success value type `S` from a `Result.Ok<S>`. * If the `Result` is `Result.Err<E>`, resolves to `never`. * @template R The `Result.Base` type to unwrap. */ export type UnwrapOk<R extends Base> = R extends Ok<infer S> ? S : never; /** * Extracts the error value type `E` from a `Result.Err<E>`. * If the `Result` is `Result.Ok<S>`, resolves to `never`. * @template R The `Result.Base` type to unwrap. */ export type UnwrapErr<R extends Base> = R extends Err<infer E> ? E : never; /** * Narrows a `Result.Base` type to `Result.Ok<S>` if it is an `Ok`. * If the `Result` is `Result.Err<E>`, resolves to `never`. * @template R The `Result.Base` type to narrow. */ export type NarrowToOk<R extends Base> = R extends Err<unknown> ? never : R; /** * Narrows a `Result.Base` type to `Result.Err<E>` if it is an `Err`. * If the `Result` is `Result.Ok<S>`, resolves to `never`. * @template R The `Result.Base` type to narrow. */ export type NarrowToErr<R extends Base> = R extends Ok<unknown> ? never : R; /** * Creates a `Result.Ok` containing the given success value. * * Use this constructor when an operation succeeds and you want to wrap * the successful result in a Result type for consistent error handling. * * @template S The type of the success value. * @param value The success value. * @returns A `Result.Ok<S>` containing the value. * @example * ```typescript * // Basic success case * const success = Result.ok(42); * console.log(Result.isOk(success)); // true * console.log(Result.unwrapOk(success)); // 42 * * // Function that returns a Result * function divide(a: number, b: number): Result<number, string> { * if (b === 0) { * return Result.err("Division by zero"); * } * return Result.ok(a / b); * } * * const result = divide(10, 2); * console.log(Result.unwrapOk(result)); // 5 * ``` */ export const ok: <S>(value: S) => Ok<S>; /** * Creates a `Result.Err` containing the given error value. * * Use this constructor when an operation fails and you want to wrap * the error information in a Result type for consistent error handling. * * @template E The type of the error value. * @param value The error value. * @returns A `Result.Err<E>` containing the value. * @example * ```typescript * // Basic error case * const failure = Result.err("Something went wrong"); * console.log(Result.isErr(failure)); // true * console.log(Result.unwrapErr(failure)); // "Something went wrong" * * // Function that can fail * function parseInteger(input: string): Result<number, string> { * const num = parseInt(input, 10); * if (isNaN(num)) { * return Result.err(`Invalid number format: ${input}`); * } * return Result.ok(num); * } * * const result = parseInteger("abc"); * console.log(Result.unwrapErr(result)); // "Invalid number format: abc" * * // Using custom error types * interface ValidationError { * field: string; * message: string; * } * * const validationError = Result.err<ValidationError>({ * field: "email", * message: "Invalid email format" * }); * ``` */ export const err: <E>(value: E) => Err<E>; /** * Checks if a `Result` is `Result.Ok`. * Acts as a type guard, narrowing the type to the success variant. * * This function is essential for type-safe Result handling, allowing * TypeScript to understand that subsequent operations will work with * the success value rather than the error value. * * @template R The `Result.Base` type to check. * @param result The `Result` to check. * @returns `true` if the `Result` is `Result.Ok`, otherwise `false`. * @example * ```typescript * // Basic type guard usage * const result: Result<number, string> = divide(10, 2); * * if (Result.isOk(result)) { * // TypeScript knows result is Result.Ok<number> * console.log(result.value); // Safe to access .value * console.log(Result.unwrapOk(result)); // 5 * } else { * // TypeScript knows result is Result.Err<string> * console.log(result.value); // Error message * } * * // Using in conditional logic * const processResult = (r: Result<string, Error>) => { * return Result.isOk(r) * ? r.value.toUpperCase() // Safe string operations * : "Error occurred"; * }; * * // Filtering arrays of Results * const results: Result<number, string>[] = [ * Result.ok(1), * Result.err("error"), * Result.ok(2) * ]; * const successes = results.filter(Result.isOk); * // successes is Result.Ok<number>[] * ``` */ export const isOk: <R extends Base>(result: R) => result is NarrowToOk<R>; /** * Checks if a `Result` is `Result.Err`. * Acts as a type guard, narrowing the type to the error variant. * * This function is essential for type-safe Result handling, allowing * TypeScript to understand that subsequent operations will work with * the error value rather than the success value. * * @template R The `Result.Base` type to check. * @param result The `Result` to check. * @returns `true` if the `Result` is `Result.Err`, otherwise `false`. * @example * ```typescript * // Basic type guard usage * const result: Result<number, string> = divide(10, 0); * * if (Result.isErr(result)) { * // TypeScript knows result is Result.Err<string> * console.log(result.value); // Safe to access error .value * console.log(Result.unwrapErr(result)); // "Division by zero" * } else { * // TypeScript knows result is Result.Ok<number> * console.log(result.value); // Success value * } * * // Error handling patterns * const handleResult = (r: Result<Data, ApiError>) => { * if (Result.isErr(r)) { * logError(r.value); // Safe error operations * return null; * } * return processData(r.value); * }; * * // Collecting errors from multiple Results * const results: Result<string, ValidationError>[] = validateForm(); * const errors = results * .filter(Result.isErr) * .map(err => err.value); // ValidationError[] * ``` */ export const isErr: <R extends Base>(result: R) => result is NarrowToErr<R>; /** * Unwraps a `Result`, returning the success value. * Throws an error if the `Result` is `Result.Err`. * * This is useful when you're confident that a Result should contain a success value * and want to treat errors as exceptional conditions. The error message will be * constructed from the error value using the provided string conversion function. * * @template R The `Result.Base` type to unwrap. * @param result The `Result` to unwrap. * @param toStr An optional function to convert the error value to a string for the error message. Defaults to `String`. * @returns The success value if `Result.Ok`. * @throws {Error} Error with the stringified error value if the `Result` is `Result.Err`. * @example * ```typescript * const success = Result.ok(42); * console.log(Result.unwrapThrow(success)); // 42 * * const failure = Result.err("Network error"); * try { * Result.unwrapThrow(failure); // throws Error: "Network error" * } catch (error) { * console.log(error.message); // "Network error" * } * ``` */ export const unwrapThrow: <R extends Base>(result: R, toStr?: (e: UnwrapErr<R>) => string) => UnwrapOk<R>; /** * Unwraps a `Result`, returning the success value or `undefined` if it's an error. * * This function provides a safe way to extract success values from Results without * throwing exceptions. It has overloaded behavior based on the type: * - For `Result.Ok<T>`: Always returns `T` (guaranteed by type system) * - For general `Result<T, E>`: Returns `T | undefined` * * @template R The `Result.Base` type to unwrap. * @param result The `Result` to unwrap. * @returns The success value if `Result.Ok`, otherwise `undefined`. * @example * ```typescript * // With guaranteed Ok - returns the value * const success = Result.ok(42); * const value = Result.unwrapOk(success); // Type: number, Value: 42 * * // With general Result - may return undefined * const maybeResult: Result<string, Error> = fetchData(); * const data = Result.unwrapOk(maybeResult); // Type: string | undefined * * // Safe pattern for handling both cases * const result = Result.ok("hello"); * const unwrapped = Result.unwrapOk(result); * if (unwrapped !== undefined) { * console.log(unwrapped.toUpperCase()); // "HELLO" * } * * // Useful in conditional chains * const processResult = (r: Result<number, string>) => { * const value = Result.unwrapOk(r); * return value !== undefined ? value * 2 : 0; * }; * ``` */ export function unwrapOk<R extends Ok<unknown>>(result: R): UnwrapOk<R>; export function unwrapOk<R extends Base>(result: R): UnwrapOk<R> | undefined; /** * Unwraps a `Result`, returning the success value or a default value if it is `Result.Err`. * @template R The `Result.Base` type to unwrap. * @template D The type of the default value. * @param result The `Result` to unwrap. * @param defaultValue The value to return if `result` is `Result.Err`. * @returns The success value if `Result.Ok`, otherwise `defaultValue`. * @example * ```typescript * const result = Result.ok(42); * const value = Result.unwrapOkOr(result, 0); * console.log(value); // 42 * ``` */ export function unwrapOkOr<R extends Base, D>(result: R, defaultValue: D): D | UnwrapOk<R>; export function unwrapOkOr<S, D>(defaultValue: D): <E>(result: Result<S, E>) => D | S; /** * Unwraps a `Result`, returning the error value. * Throws an error if the `Result` is `Result.Ok`. * * This function is used when you expect a Result to be an error and want to * extract the error value. If the Result is unexpectedly Ok, it will throw * an error with information about the unexpected success value. * * @template R The `Result.Base` type to unwrap. * @param result The `Result` to unwrap. * @param toStr An optional function to convert the success value to a string for the error message when the Result is unexpectedly Ok. Defaults to `String`. * @returns The error value if `Result.Err`. * @throws {Error} Error with message "Expected Err but got Ok: {value}" if the `Result` is `Result.Ok`. * @example * ```typescript * const failure = Result.err("Network timeout"); * console.log(Result.unwrapErrThrow(failure)); // "Network timeout" * * const success = Result.ok(42); * try { * Result.unwrapErrThrow(success); // throws Error: "Expected Err but got Ok: 42" * } catch (error) { * console.log(error.message); // "Expected Err but got Ok: 42" * } * ``` */ export const unwrapErrThrow: <R extends Base>(result: R, toStr?: (v: UnwrapOk<R>) => string) => UnwrapErr<R>; /** * Unwraps a `Result`, returning the error value or `undefined` if it is `Result.Ok`. * * This provides a safe way to extract error values from Results without throwing * exceptions. Useful for error handling patterns where you want to check for * specific error conditions. * * @template R The `Result.Base` type to unwrap. * @param result The `Result` to unwrap. * @returns The error value if `Result.Err`, otherwise `undefined`. * @example * ```typescript * const failure = Result.err("Connection failed"); * console.log(Result.unwrapErr(failure)); // "Connection failed" * * const success = Result.ok(42); * console.log(Result.unwrapErr(success)); // undefined * ``` */ export const unwrapErr: <R extends Base>(result: R) => UnwrapErr<R> | undefined; /** * Unwraps a `Result`, returning the error value or a default value if it is `Result.Ok`. * @template R The `Result.Base` type to unwrap. * @template D The type of the default value. * @param result The `Result` to unwrap. * @param defaultValue The value to return if `result` is `Result.Ok`. * @returns The error value if `Result.Err`, otherwise `defaultValue`. * @example * ```typescript * const result = Result.err("failed"); * const error = Result.unwrapErrOr(result, "default"); * console.log(error); // "failed" * ``` */ export function unwrapErrOr<R extends Base, D>(result: R, defaultValue: D): D | UnwrapErr<R>; export function unwrapErrOr<E, D>(defaultValue: D): <S>(result: Result<S, E>) => D | E; /** * Maps a `Result<S, E>` to `Result<S2, E>` by applying a function to the success value. * If the `Result` is `Result.Err`, returns the original `Err`. * @template R The input `Result.Base` type. * @template S2 The type of the success value returned by the mapping function. * @param result The `Result` to map. * @param mapFn The function to apply to the success value if present. * @returns A new `Result<S2, UnwrapErr<R>>`. * @example * ```typescript * // Regular usage * const result = Result.ok(5); * const mapped = Result.map(result, x => x * 2); * console.log(Result.unwrap(mapped)); // 10 * * // Curried version for use with pipe * const doubler = Result.map((x: number) => x * 2); * const result2 = pipe(Result.ok(5)).map(doubler).value; * console.log(Result.unwrap(result2)); // 10 * ``` */ export function map<R extends Base, S2>(result: R, mapFn: (value: UnwrapOk<R>) => S2): Result<S2, UnwrapErr<R>>; export function map<S, S2>(mapFn: (value: S) => S2): <E>(result: Result<S, E>) => Result<S2, E>; /** * Maps a `Result<S, E>` to `Result<S, E2>` by applying a function to the error value. * If the `Result` is `Result.Ok`, returns the original `Ok`. * @template R The input `Result.Base` type. * @template E2 The type of the error value returned by the mapping function. * @param result The `Result` to map. * @param mapFn The function to apply to the error value if present. * @returns A new `Result<UnwrapOk<R>, E2>`. * @example * ```typescript * const result = Result.err("error"); * const mapped = Result.mapErr(result, e => e.toUpperCase()); * console.log(Result.unwrapErr(mapped)); // "ERROR" * ``` */ export function mapErr<R extends Base, E2>(result: R, mapFn: (error: UnwrapErr<R>) => E2): Result<UnwrapOk<R>, E2>; export function mapErr<E, E2>(mapFn: (error: E) => E2): <S>(result: Result<S, E>) => Result<S, E2>; /** * Applies one of two functions depending on whether the `Result` is `Ok` or `Err`. * @template R The input `Result.Base` type. * @template S2 The type of the success value returned by `mapFn`. * @template E2 The type of the error value returned by `mapErrFn`. * @param result The `Result` to fold. * @param mapFn The function to apply if `result` is `Ok`. * @param mapErrFn The function to apply if `result` is `Err`. * @returns A new `Result<S2, E2>` based on the applied function. * @example * ```typescript * const result = Result.ok(42); * const folded = Result.fold(result, x => x * 2, () => 0); * console.log(Result.unwrapOk(folded)); // 84 * ``` */ export function fold<R extends Base, S2, E2>(result: R, mapFn: (value: UnwrapOk<R>) => S2, mapErrFn: (error: UnwrapErr<R>) => E2): Result<S2, E2>; export function fold<S, E, S2, E2>(mapFn: (value: S) => S2, mapErrFn: (error: E) => E2): (result: Result<S, E>) => Result<S2, E2>; /** * Applies a function that returns a `Result` to the success value of a `Result`. * If the input is `Err`, returns the original `Err`. * This is the monadic bind operation for `Result`. * @template R The input `Result.Base` type. * @template S2 The success type of the `Result` returned by the function. * @template E2 The error type of the `Result` returned by the function. * @param result The `Result` to flat map. * @param flatMapFn The function to apply that returns a `Result`. * @returns The result of applying the function, or the original `Err`. * @example * ```typescript * const divide = (a: number, b: number): Result<number, string> => * b === 0 ? Result.err("Division by zero") : Result.ok(a / b); * * const result = Result.flatMap(Result.ok(10), x => divide(x, 2)); * console.log(Result.unwrapOk(result)); // 5 * ``` */ export function flatMap<R extends Base, S2, E2>(result: R, flatMapFn: (value: UnwrapOk<R>) => Result<S2, E2>): Result<S2, E2 | UnwrapErr<R>>; export function flatMap<S, S2, E2>(flatMapFn: (value: S) => Result<S2, E2>): <E>(result: Result<S, E>) => Result<S2, E | E2>; /** * Unwraps a `Result`, returning the success value or throwing an error with the provided message. * @template R The `Result.Base` type to unwrap. * @param result The `Result` to unwrap. * @param message The error message to throw if the `Result` is `Result.Err`. * @returns The success value if `Result.Ok`. * @throws Error with the provided message if the `Result` is `Result.Err`. * @example * ```typescript * const result = Result.ok(42); * const value = Result.expectToBe(result, "Operation must succeed"); * console.log(value); // 42 * ``` */ export function expectToBe<R extends Base>(result: R, message: string): UnwrapOk<R>; export function expectToBe<S>(message: string): <E>(result: Result<S, E>) => S; /** * @internal * Utility type to extract the resolved value type from a Promise. * @template P The Promise type. * @example * UnwrapPromise<Promise<string>> // string * UnwrapPromise<Promise<number>> // number */ type UnwrapPromise<P extends Promise<unknown>> = P extends Promise<infer V> ? V : never; /** * Converts a Promise into a Promise that resolves to a `Result`. * If the input Promise resolves, the `Result` will be `Ok` with the resolved value. * If the input Promise rejects, the `Result` will be `Err` with the rejection reason. * @template P The type of the input Promise. * @param promise The Promise to convert. * @returns A Promise that resolves to `Result<UnwrapPromise<P>, unknown>`. */ export const fromPromise: <P extends Promise<unknown>>(promise: P) => Promise<Result<UnwrapPromise<P>, unknown>>; /** * Wraps a function that may throw an exception in a `Result`. * * This is a fundamental utility for converting traditional exception-based error * handling into Result-based error handling. Any thrown value is converted to an * Error object for consistent error handling. * * If the function executes successfully, returns `Result.Ok` with the result. * If the function throws, returns `Result.Err` with the caught error. * * @template T The return type of the function. * @param fn The function to execute that may throw. * @returns A `Result<T, Error>` containing either the successful result or the caught error. * @example * ```typescript * // Wrapping JSON.parse which can throw * const parseJson = <T>(text: string): Result<T, Error> => * Result.fromThrowable(() => JSON.parse(text) as T); * * const validJson = parseJson<{valid: boolean}>('{"valid": true}'); * if (Result.isOk(validJson)) { * console.log(validJson.value.valid); // true * } * * ``` */ export const fromThrowable: <T>(fn: () => T) => Result<T, Error>; /** * Swaps the success and error values of a `Result`. * @template R The input `Result.Base` type. * @param result The `Result` to swap. * @returns A new `Result` with success and error swapped. * @example * ```typescript * const okResult = Result.ok(42); * const swapped = Result.swap(okResult); * console.log(Result.isErr(swapped)); // true * console.log(Result.unwrapErr(swapped)); // 42 * ``` */ export const swap: <R extends Base>(result: R) => Result<UnwrapErr<R>, UnwrapOk<R>>; /** * Converts a `Result` to an `Optional`. * * This conversion is useful when you want to discard error information and only * care about whether an operation succeeded. The error information is lost in * this conversion, so use it when error details are not needed. * * If the `Result` is `Ok`, returns `Some` with the value. * If the `Result` is `Err`, returns `None`. * * @template R The input `Result.Base` type. * @param result The `Result` to convert. * @returns An `Optional<UnwrapOk<R>>` containing the success value or representing `None`. * @example * ```typescript * // Basic conversion * const okResult = Result.ok(42); * const optional = Result.toOptional(okResult); * console.log(Optional.isSome(optional)); // true * console.log(Optional.unwrap(optional)); // 42 * * const errResult = Result.err("Network error"); * const none = Result.toOptional(errResult); * console.log(Optional.isNone(none)); // true * * ``` */ export const toOptional: <R extends Base>(result: R) => Optional<UnwrapOk<R>>; /** * Returns the `Result` if it is `Ok`, otherwise returns the alternative. * @template R The input `Result.Base` type. * @param result The `Result` to check. * @param alternative The alternative `Result` to return if the first is `Err`. * @returns The first `Result` if `Ok`, otherwise the alternative. * @example * ```typescript * const primary = Result.err("error"); * const fallback = Result.ok("default"); * const result = Result.orElse(primary, fallback); * console.log(Result.unwrapOk(result)); // "default" * ``` */ export function orElse<R extends Base, R2 extends Base>(result: R, alternative: R2): NarrowToOk<R> | R2; export function orElse<S, E, S2, E2>(alternative: Result<S2, E2>): (result: Result<S, E>) => Result<S, E> | Result<S2, E2>; /** * Combines two `Result` values into a single `Result` containing a tuple. * If either `Result` is `Err`, returns the first `Err` encountered. * @template S1 The success type of the first `Result`. * @template E1 The error type of the first `Result`. * @template S2 The success type of the second `Result`. * @template E2 The error type of the second `Result`. * @param resultA The first `Result`. * @param resultB The second `Result`. * @returns A `Result` containing a tuple of both values, or the first `Err`. * @example * ```typescript * const a = Result.ok(1); * const b = Result.ok("hello"); * const zipped = Result.zip(a, b); * console.log(Result.unwrapOk(zipped)); // [1, "hello"] * * const withErr = Result.zip(a, Result.err("error")); * console.log(Result.unwrapErr(withErr)); // "error" * ``` */ export const zip: <S1, E1, S2, E2>(resultA: Result<S1, E1>, resultB: Result<S2, E2>) => Result<readonly [S1, S2], E1 | E2>; export {}; } export {}; //# sourceMappingURL=result.d.mts.map