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 {};
