ts-safe
Version:
A functional, type-safe utility library for elegant error handling and asynchronous operations in JavaScript/TypeScript.
182 lines (174 loc) • 8.98 kB
TypeScript
type SafeResult<T = any> = {
isOk: false;
error: Error;
value?: undefined;
} | {
isOk: true;
error?: undefined;
value: T;
};
/**
* Represents a safe container for values that handles errors gracefully
* and supports both synchronous and asynchronous operations.
*/
interface Safe<T> {
/**
* Transforms the value inside the safe container.
* If the container has an error, the transform is not applied.
*
* @param transform Function to transform the value
* @returns A new Safe containing the transformed value
*/
map<U>(transform: (value: T extends PromiseLike<any> ? Awaited<T> : T) => U): U extends PromiseLike<any> ? Safe<U> : T extends PromiseLike<any> ? Safe<Promise<U>> : Safe<U>;
/**
* Transforms the value with a function that returns another Safe.
* Used for flattening nested Safe containers.
*
* @param transform Function that returns another Safe
* @returns A flattened Safe container
*/
flatMap<U>(transform: (value: T extends PromiseLike<any> ? Awaited<T> : T) => Safe<U>): U extends PromiseLike<any> ? Safe<U> : T extends PromiseLike<any> ? Safe<Promise<U>> : Safe<U>;
/**
* Observes the current state without affecting it.
* Provides access to both value and error information.
* Any errors thrown inside this function are ignored.
*
* @param consumer Function to observe the current state
* @returns The same Safe, preserving the original value
*/
watch(consumer: (result: T extends PromiseLike<any> ? SafeResult<Awaited<T>> : SafeResult<T>) => any): Safe<T>;
/**
* Applies a side effect to the value.
* Errors thrown inside this function will propagate through the chain.
* If the function returns a Promise, the chain becomes asynchronous.
*
* @param effectFn Function to apply a side effect
* @returns The same Safe with possibly different promise state
*/
effect<U>(effectFn: (value: T extends PromiseLike<any> ? Awaited<T> : T) => U): T extends PromiseLike<any> ? Safe<T> : U extends PromiseLike<any> ? Safe<Promise<T>> : Safe<T>;
/**
* Recovers from an error by providing a fallback value.
* If there's no error, the original value is kept.
*
* @param handler Function that returns a fallback value
* @returns A Safe with either the original value or recovery value
*/
catch<U>(handler: (error: Error) => U): Safe<T extends PromiseLike<any> ? Promise<Awaited<T> | (U extends PromiseLike<any> ? Awaited<U> : U)> : T | U>;
/**
* Indicates if the Safe contains a success value.
* Returns a Promise for asynchronous operations.
*/
isOk: T extends PromiseLike<any> ? Promise<boolean> : boolean;
/**
* Extracts the value from the Safe.
* Throws if there's an error.
*
* @returns The value (or Promise<value> for async operations)
* @throws The error if present
*/
unwrap(): T;
/**
* Extracts the value or returns a fallback if there's an error.
* Never throws an exception.
*
* @param fallback The value to return if there's an error
* @returns The success value or the fallback value
*/
orElse<U>(fallback: U): T extends PromiseLike<any> ? Promise<Awaited<T> | U> : T | U;
}
/**
* Type for watch function parameters.
*/
type WatchFuncion<T = unknown> = Parameters<Safe<T>['watch']>[0];
type NonDistributive<T> = [T] extends [any] ? T : never;
type HasPromise<T> = NonDistributive<T> extends Promise<any> ? true : (T extends any ? (T extends Promise<any> ? true : false) : never) extends false ? false : true;
type SafeCheckPromise<T, U> = HasPromise<U> extends true ? Safe<Promise<Awaited<T>>> : Safe<T>;
type SafeMap<A, B> = (input: A extends PromiseLike<any> ? Awaited<A> : A) => B;
declare function safePipe<Input, A>(ab: SafeMap<Input, A>): (input: Input) => SafeCheckPromise<A, Input>;
declare function safePipe<Input, A, B>(a: SafeMap<Input, A>, b: SafeMap<A, B>): (input: Input) => SafeCheckPromise<B, A | Input>;
declare function safePipe<Input, A, B, C>(a: SafeMap<Input, A>, b: SafeMap<A, B>, c: SafeMap<B, C>): (input: Input) => SafeCheckPromise<C, A | B | Input>;
declare function safePipe<Input, A, B, C, D>(a: SafeMap<Input, A>, b: SafeMap<A, B>, c: SafeMap<B, C>, d: SafeMap<C, D>): (input: Input) => SafeCheckPromise<D, A | B | C | Input>;
declare function safePipe<Input, A, B, C, D, E>(a: SafeMap<Input, A>, b: SafeMap<A, B>, c: SafeMap<B, C>, d: SafeMap<C, D>, e: SafeMap<D, E>): (input: Input) => SafeCheckPromise<E, A | B | C | D | Input>;
declare function safePipe<Input, A, B, C, D, E, F>(a: SafeMap<Input, A>, b: SafeMap<A, B>, c: SafeMap<B, C>, d: SafeMap<C, D>, e: SafeMap<D, E>, f: SafeMap<E, F>): (input: Input) => SafeCheckPromise<F, A | B | C | D | E | Input>;
declare function safePipe<Input, A, B, C, D, E, F, G>(a: SafeMap<Input, A>, b: SafeMap<A, B>, c: SafeMap<B, C>, d: SafeMap<C, D>, e: SafeMap<D, E>, f: SafeMap<E, F>, g: SafeMap<F, G>): (input: Input) => SafeCheckPromise<G, A | B | C | D | E | F | Input>;
/**
* Creates a validator function that throws an error if the value is null or undefined.
*
* @template T - The type of the value to validate
* @param {string} [message='Value is null or undefined'] - The error message to throw
* @returns {function(T): T} A function that validates input and returns it if valid
* @throws {Error} If the value is null or undefined
*/
declare const errorIfNull: <T = unknown>(message?: string) => ((value: T) => T);
/**
* Creates a validator function that throws an error if the value is falsy.
* Falsy values include: null, undefined, empty string, 0, false, NaN.
*
* @template T - The type of the value to validate
* @param {string} [message='Value is falsy'] - The error message to throw
* @returns {function(T): T} A function that validates input and returns it if valid
* @throws {Error} If the value is falsy
*/
declare const errorIfFalsy: <T = unknown>(message?: string) => ((value: T) => T);
/**
* Creates a validator function that throws an error if the array or string is empty.
*
* @template T - The type of the value to validate (must have a length property)
* @param {string} [message='Value is empty'] - The error message to throw
* @returns {function(T): T} A function that validates input and returns it if valid
* @throws {Error} If the value has a length of 0
*/
declare const errorIfEmpty: <T extends {
length: number;
}>(message?: string) => ((value: T) => T);
/**
* Creates a validator function that throws an error based on a custom condition.
*
* @template T - The type of the value to validate
* @param {function(T): (string|false|undefined)} check - Function that should return an error message
* if validation fails, or false/undefined if validation passes
* @returns {function(T): T} A function that validates input and returns it if valid
* @throws {Error} If the check function returns a string (error message)
*/
declare const errorIf: <T>(check: (value: T) => string | false | undefined) => ((value: T) => T);
/**
* Creates a function that observes and processes errors in a SafeResult.
* This utility only calls the consumer function when the result contains an error.
*
* @param {function(Error): any} consumer - Function to process the error
* @returns {function(SafeResult): void} A function that calls the consumer only if the result has an error
*/
declare const watchError: (consumer: (error: Error) => any) => (result: SafeResult) => void;
/**
* Creates a function that observes and processes success values in a SafeResult.
* This utility only calls the consumer function when the result contains a success value.
*
* @template T - The type of the success value
* @param {function(T): any} consumer - Function to process the success value
* @returns {function(SafeResult<T>): void} A function that calls the consumer only if the result has a success value
*/
declare const watchOk: <T>(consumer: (value: T) => any) => (result: SafeResult<T>) => void;
/**
* Creates a function that will automatically retry a failed operation
* @param fn The function to retry
* @param options Configuration options for retry behavior
* @returns A wrapped function that implements retry logic
*/
declare const retry: <T, U>(fn: (arg: T) => Promise<U> | U, options?: {
maxTries?: number;
delay?: number;
backoff?: boolean;
}) => (arg: T) => Promise<U>;
/**
*
* @param init Optional value or function that returns a value
* @returns A Safe containing the value or function result
*/
declare function safe<T>(init: () => T): Safe<T>;
declare function safe<T>(init: T): Safe<T>;
declare function safe(): Safe<undefined>;
declare namespace safe {
var pipe: typeof safePipe;
}
declare const s: typeof safe;
export { type Safe, type SafeResult, type WatchFuncion, errorIf, errorIfEmpty, errorIfFalsy, errorIfNull, retry, s, safe, safePipe, watchError, watchOk };