typescript-functional-extensions
Version:
A TypeScript implementation of synchronous and asynchronous Maybe and Result monads
386 lines (381 loc) • 19.9 kB
TypeScript
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 {};