UNPKG

typescript-functional-extensions

Version:

A TypeScript implementation of synchronous and asynchronous Maybe and Result monads

386 lines (381 loc) 19.9 kB
import { ResultAsync } from './resultAsync.js'; import { Unit } from './unit.js'; import { Action, ActionOfT, AsyncAction, AsyncActionOfT, ErrorHandler, FunctionOfT, FunctionOfTtoK, None, Predicate, PredicateOfT, ResultMatcher, ResultMatcherNoReturn, Some } from './utilities.js'; /** * Allows to extract the Value of the given `Result` or `ResultAsync` * * @example ResultValue<Result<string>> => string * @example ResultValue<ResultAsync<string>> => string */ export type ResultValue<T> = T extends Result<infer TResultValue> ? TResultValue : T extends ResultAsync<infer TResultAsyncValue> ? TResultAsyncValue : never; export type ResultRecord<TResultRecord> = { [K in keyof TResultRecord]: ResultValue<TResultRecord[K]>; }; /** * Represents a successful Result operation. */ type ResultSuccess<TValue> = Result<TValue> & { value: TValue; }; /** * Represents a failed Result operation. */ type ResultFailure<TValue, TError> = Result<TValue> & { error: TError; }; /** * Represents a successful or failed operation */ export declare class Result<TValue = Unit, TError = string> { /** * Combines several results (and any error messages) into a single result. * The returned result will be a failure if any of the input results are failures. * * @param results The Results to be combined. * @returns A Result that is a success when all the input results are also successes. */ static combine<TResultRecord extends Record<string, Result<unknown>>>(results: TResultRecord): Result<ResultRecord<TResultRecord>>; static combineAsync<TResultRecord extends Record<string, Result<unknown> | ResultAsync<unknown>>>(record: TResultRecord): ResultAsync<ResultRecord<TResultRecord>>; static combineInOrderAsync<TResultRecord extends Record<string, Result<unknown> | ResultAsync<unknown>>>(record: TResultRecord): ResultAsync<ResultRecord<TResultRecord>>; /** * Creates a new successful Result with a string error type * and Unit value type */ static success(): Result<Unit, string>; /** * Creates a new successful Result with the given value * @param value the result of the successful operation */ static success<TValue, TError = string>(value: Some<TValue>): Result<TValue, TError>; static successIf<TValue = Unit, TError = string>(condition: boolean, state: { value: Some<TValue>; error: Some<TError>; }): Result<TValue, TError>; static successIf<TValue = Unit, TError = string>(predicate: Predicate, state: { value: Some<TValue>; error: Some<TError>; }): Result<TValue, TError>; /** * Creates a new failed Result * @param error the error of the failed operation * @returns new failed Result */ static failure<TValue = Unit, TError = string>(error: Some<TError>): Result<TValue, TError>; static failureIf<TValue = Unit, TError = string>(condition: boolean, state: { value: Some<TValue>; error: Some<TError>; }): Result<TValue, TError>; static failureIf<TValue = Unit, TError = string>(predicate: Predicate, state: { value: Some<TValue>; error: Some<TError>; }): Result<TValue, TError>; /** * Returns only the values of successful Results * @param results */ static choose<TValue, TError>(results: Result<TValue, TError>[]): TValue[]; /** * Returns only the values of successful Results, mapped to new values * with the given selector function * @param results * @param projection */ static choose<TValue, TNewValue, TError>(results: Result<TValue, TError>[], projection: FunctionOfTtoK<TValue, TNewValue>): TNewValue[]; /** * Creates a new successful Result with the return value * of the given factory function. If the function throws, a failed Result will * be returned with an error created by the provided errorHandler * @param factory * @param errorHandler */ static try<TValue, TError = string>(factory: FunctionOfT<Some<TValue>>, errorHandler: ErrorHandler<TError>): Result<TValue, TError>; /** * Creates a new successful Result with a Unit value. * If the function throws, a failed Result will * be returned with an error created by the provided errorHandler * @param action * @param errorHandler */ static try<TError = string>(action: Action, errorHandler: ErrorHandler<TError>): Result<Unit, TError>; /** * True if the result operation succeeded */ get isSuccess(): boolean; /** * True if the result operation failed. */ get isFailure(): boolean; /** * Yields value if the result operation succeeded. * Hint: Use hasValue() upfront to be sure that result operation succeeded. */ protected get value(): Some<TValue> | undefined; /** * Yields error if the result operation failed. * Hint: Use hasError() upfront to be sure that result operation failed. */ protected get error(): Some<TError> | undefined; /** * Checks if result operation succeeded. */ hasValue(): this is ResultSuccess<TValue>; /** * Checks if result operation failed. */ hasError(): this is ResultFailure<TValue, TError>; /** * The internal state of the Result */ private state; /** * Creates a new Result instance in a guaranteed valid state * @param {{ value?: TValue, error?: TError, isSuccess: boolean }} state the initial state of the Result * @throws {Error} if the provided initial state is invalid */ protected constructor(state: { value: Some<TValue> | None; error: Some<TError> | None; isSuccess: boolean; }); /** * Gets the Result's inner value * @returns {TValue} the inner value if the result suceeded * @throws {Error} if the result failed */ getValueOrThrow(): Some<TValue>; /** * Returns the Result's value if it is successful and the default otherwise * @param defaultValue a value to return if the Result is failed */ getValueOrDefault(defaultValue: Some<TValue>): Some<TValue>; /** * Returns the Result's value if it is successful and the evaluation of the factory function otherwise * @param factory a function which is executed and returned if the Result is failed */ getValueOrDefault(factory: FunctionOfT<Some<TValue>>): Some<TValue>; /** * Gets the Result's inner error * @returns {TError} the inner error if the operation failed * @throws {Error} if the result succeeded */ getErrorOrThrow(): Some<TError>; /** * Gets the Result's inner error * @param defaultOrErrorFactory An error or error creator function * @returns {TError} The Result's error or a default error if the Result succeeded */ getErrorOrDefault(error: Some<TError>): Some<TError>; getErrorOrDefault(errorFactory: FunctionOfT<Some<TError>>): Some<TError>; /** * If the Result has failed, the result is returned. * Otherwise, it executes the predicate and returns a failed Result with the given error * if the predicate returns false, and the current Result if it returns true * @param predicate check against the Result's inner value * @param error An error for the returned Result if the predicate returns false */ ensure(predicate: PredicateOfT<TValue>, error: Some<TError>): Result<TValue, TError>; /** * If the Result has failed, the result is returned. * Otherwise, it executes the predicate and returns a failed Result with an error created from the errorFactory * if the predicate returns false, and the current Result if it returns true * @param predicate check against the Result's inner value * @param errorFactory A function provided the Result's value, used to create an error for the returned Result if the predicate returns false */ ensure(predicate: PredicateOfT<TValue>, errorFactory: FunctionOfTtoK<TValue, Some<TError>>): Result<TValue, TError>; /** * Returns a successful Result with the current value if the projection returns a successful Result * @param projection a function given the current Result's value and returns a new Result * @returns If the Result has failed, it is returned. Otherwise, the projection is executed. * If the projection returns a successful Result, a successful Result with the original value is returned. * If the projection returns a failed Result it is returned. */ check<TOtherValue>(projection: FunctionOfTtoK<TValue, Result<TOtherValue, TError>>): Result<TValue, TError>; /** * Similar to check, but the projection is only executed if the Result has succeeded and the condition is true * @param condition * @param projection */ checkIf<TOtherValue>(condition: boolean, projection: FunctionOfTtoK<TValue, Result<TOtherValue, TError>>): Result<TValue, TError>; /** * Similiar to check, but the projection is only executed if the Result has succeeded and the predicate returns true * @param predicate * @param projection */ checkIf<TOtherValue>(predicate: PredicateOfT<TValue>, projection: FunctionOfTtoK<TValue, Result<TOtherValue, TError>>): Result<TValue, TError>; pipe(): Result<TValue, TError>; pipe<A, AE>(op1: ResultOpFnAsync<TValue, TError, A, AE>): ResultAsync<A, AE>; pipe<A, AE>(op1: ResultOpFn<TValue, TError, A, AE>): Result<A, AE>; pipe<A, AE, B, BE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFnAsync<A, AE, B, BE>): ResultAsync<B, BE>; pipe<A, AE, B, BE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>): Result<B, BE>; pipe<A, AE, B, BE, C, CE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>, op3: ResultOpFnAsync<B, BE, C, CE>): ResultAsync<C, CE>; pipe<A, AE, B, BE, C, CE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>, op3: ResultOpFn<B, BE, C, CE>): Result<C, CE>; pipe<A, AE, B, BE, C, CE, D, DE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>, op3: ResultOpFn<B, BE, C, CE>, op4: ResultOpFnAsync<C, CE, D, DE>): ResultAsync<D, DE>; pipe<A, AE, B, BE, C, CE, D, DE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>, op3: ResultOpFn<B, BE, C, CE>, op4: ResultOpFn<C, CE, D, DE>): Result<D, DE>; pipe<A, AE, B, BE, C, CE, D, DE, E, EE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>, op3: ResultOpFn<B, BE, C, CE>, op4: ResultOpFn<C, CE, D, DE>, op5: ResultOpFnAsync<D, DE, E, EE>): ResultAsync<E, EE>; pipe<A, AE, B, BE, C, CE, D, DE, E, EE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>, op3: ResultOpFn<B, BE, C, CE>, op4: ResultOpFn<C, CE, D, DE>, op5: ResultOpFn<D, DE, E, EE>): Result<E, EE>; pipe<A, AE, B, BE, C, CE, D, DE, E, EE, F, FE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>, op3: ResultOpFn<B, BE, C, CE>, op4: ResultOpFn<C, CE, D, DE>, op5: ResultOpFn<D, DE, E, EE>, op6: ResultOpFnAsync<E, EE, F, FE>): ResultAsync<F, FE>; pipe<A, AE, B, BE, C, CE, D, DE, E, EE, F, FE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>, op3: ResultOpFn<B, BE, C, CE>, op4: ResultOpFn<C, CE, D, DE>, op5: ResultOpFn<D, DE, E, EE>, op6: ResultOpFn<E, EE, F, FE>): Result<F, FE>; pipe<A, AE, B, BE, C, CE, D, DE, E, EE, F, FE, G, GE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>, op3: ResultOpFn<B, BE, C, CE>, op4: ResultOpFn<C, CE, D, DE>, op5: ResultOpFn<D, DE, E, EE>, op6: ResultOpFn<E, EE, F, FE>, op7: ResultOpFnAsync<F, FE, G, GE>): ResultAsync<G, GE>; pipe<A, AE, B, BE, C, CE, D, DE, E, EE, F, FE, G, GE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>, op3: ResultOpFn<B, BE, C, CE>, op4: ResultOpFn<C, CE, D, DE>, op5: ResultOpFn<D, DE, E, EE>, op6: ResultOpFn<E, EE, F, FE>, op7: ResultOpFn<F, FE, G, GE>): Result<G, GE>; pipe<A, AE, B, BE, C, CE, D, DE, E, EE, F, FE, G, GE, H, HE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>, op3: ResultOpFn<B, BE, C, CE>, op4: ResultOpFn<C, CE, D, DE>, op5: ResultOpFn<D, DE, E, EE>, op6: ResultOpFn<E, EE, F, FE>, op7: ResultOpFn<F, FE, G, GE>, op8: ResultOpFnAsync<G, GE, H, HE>): ResultAsync<H, HE>; pipe<A, AE, B, BE, C, CE, D, DE, E, EE, F, FE, G, GE, H, HE>(op1: ResultOpFn<TValue, TError, A, AE>, op2: ResultOpFn<A, AE, B, BE>, op3: ResultOpFn<B, BE, C, CE>, op4: ResultOpFn<C, CE, D, DE>, op5: ResultOpFn<D, DE, E, EE>, op6: ResultOpFn<E, EE, F, FE>, op7: ResultOpFn<F, FE, G, GE>, op8: ResultOpFn<G, FE, H, HE>): Result<H, HE>; /** * Maps the value successful Result to a new value * @param projection a function given the value of the current Result which returns a new value * @returns If the Result has failed, a new one with the same error is returned. * Otherwise a new successful Result is returned with the value of the projection. */ map<TNewValue>(projection: FunctionOfTtoK<TValue, Some<TNewValue>>): Result<TNewValue, TError>; /** * Maps the error of a failed Result to a new error * @param projection a function given the error of the current Result which returns a new error * @returns If the Result has succeeded, a new one with the same value is returned. * Otherwise a new failed Result is returned with the error created by the projection. */ mapError<TNewError>(projection: FunctionOfTtoK<TError, Some<TNewError>>): Result<TValue, TNewError>; /** * Converts a failed Result into a successful one * @param projection a function that maps the error of the current Result to a value * @returns A successful Result using the current Result's value if it succeeded and the projection's value if it failed */ mapFailure(projection: FunctionOfTtoK<TError, Some<TValue>>): Result<TValue, TError>; /** * Maps the value successful Result to a new async value wrapped in a ResultAsync * @param projection a function given the value of the current Result which returns a Promise of some value * @returns */ mapAsync<TNewValue>(projection: FunctionOfTtoK<TValue, Promise<Some<TNewValue>>>): ResultAsync<TNewValue, TError>; /** * Maps the error of a failed Result to a new async value wrapped in a ResultAsync * @param projection a function given the error of the current Result which returns a Promise of some value * @returns */ mapFailureAsync(projection: FunctionOfTtoK<TError, Promise<Some<TValue>>>): ResultAsync<TValue, TError>; /** * Maps a successful Result to a new Result * @param projection a function given the value of the current Result which returns a new Result of some value * @returns */ bind<TNewValue>(projection: FunctionOfTtoK<TValue, Result<TNewValue, TError>>): Result<TNewValue, TError>; /** * Maps a successful Result to a new ResultAsync * @param projection */ bindAsync<TNewValue>(projection: FunctionOfTtoK<TValue, Promise<Result<TNewValue, TError>>>): ResultAsync<TNewValue, TError>; /** * Maps a successful Result to a new ResultAsync * @param projection */ bindAsync<TNewValue>(projection: FunctionOfTtoK<TValue, ResultAsync<TNewValue, TError>>): ResultAsync<TNewValue, TError>; /** * Maps a failed Result to a new Result * @deprecated Please use `compensate` instead * @param projection * @returns */ bindFailure(projection: FunctionOfTtoK<TError, Result<TValue, TError>>): Result<TValue, TError>; /** * Maps a failed Result to a new Result * @param projection * @returns */ compensate(projection: FunctionOfTtoK<TError, Result<TValue, TError>>): Result<TValue, TError>; /** * Maps a failed Result to a new ResultAsync * @deprecated Please use `compensateAsync` instead * @param projection * @returns */ bindFailureAsync(projection: FunctionOfTtoK<TError, Promise<Result<TValue, TError>> | ResultAsync<TValue, TError>>): ResultAsync<TValue, TError>; /** * Maps a failed Result to a new ResultAsync * @param projection * @returns */ compensateAsync(projection: FunctionOfTtoK<TError, Promise<Result<TValue, TError>> | ResultAsync<TValue, TError>>): ResultAsync<TValue, TError>; /** * Executes an action if the current Result has succeeded * @param action a function given the value of the current Result * @returns the current Result */ tap(action: ActionOfT<TValue>): Result<TValue, TError>; /** * Executes an action if the current Result has failed * @param action a function given the error of the current Result * @returns the current Result */ tapFailure(action: ActionOfT<TError>): Result<TValue, TError>; /** * Executes an async action if the Result succeeded * @param action a function given the Result's value returns a Promise * @returns a ResultAsync */ tapAsync(action: AsyncActionOfT<TValue>): ResultAsync<TValue, TError>; /** * Executes an action if the given condition is true and the Result has succeeded * @param condition a boolean value * @param action a function given the Result's value * @returns the current Result */ tapIf(condition: boolean, action: ActionOfT<TValue>): Result<TValue, TError>; /** * Executes and action if the given predicate evaluates to true and the Result has succeeded * @param predicate a function given the Result's value and returns a boolean * @param action a function given the Result's value * @returns the current Result */ tapIf(predicate: PredicateOfT<TValue>, action: ActionOfT<TValue>): Result<TValue, TError>; /** * Executes the action on both success and failure. * @param action a function with no parameters returning no value * @returns the current Result */ tapEither(action: Action): Result<TValue, TError>; /** * Executes the asynchronous action on both success and failure. * @param action a function * @returns the current Result wrapped in a ResultAsync */ tapEitherAsync(action: AsyncAction): ResultAsync<TValue, TError>; /** * Maps a successful Result's value to a new value, * or a failed Result's error to a new value * @param matcher */ match<TNewValue>(matcher: ResultMatcher<TValue, TError, TNewValue>): TNewValue; /** * Executes an action for a Result in either the successful and failed state * @param matcher */ match(matcher: ResultMatcherNoReturn<TValue, TError>): Unit; /** * Executes the same function for both failed and successful Results * @param projection * @returns */ finally<TNewValue>(projection: FunctionOfTtoK<Result<TValue, TError>, Some<TNewValue>>): Some<TNewValue>; /** * * @param action * @param errorHandler * @returns */ onSuccessTry(action: ActionOfT<TValue>, errorHandler: ErrorHandler<TError>): Result<TValue, TError>; /** * * @param asyncAction * @param errorHander * @returns */ onSuccessTryAsync(asyncAction: FunctionOfTtoK<TValue, Promise<void>>, errorHander: ErrorHandler<TError>): ResultAsync<TValue, TError>; /** * Returns a string representation of the Result state (success/failure) * @returns */ toString(): string; debug(): string; equals(result: Result<TValue, TError>): boolean; } export type ResultOpFn<A, AE, B, BE> = FunctionOfTtoK<Result<A, AE>, Result<B, BE>>; export type ResultOpFnAsync<A, AE, B, BE> = FunctionOfTtoK<Result<A, AE>, ResultAsync<B, BE>>; export {};