UNPKG

data.task.ts

Version:

Personal functional Task typeclass implementation

202 lines (201 loc) 10.1 kB
import { Either } from 'monet'; type GetTaskSuccess<T> = T extends Task<unknown, infer R> ? R : never; type GetTaskFailure<T> = T extends Task<infer F, unknown> ? F : never; type RemapTasks<T> = T extends readonly (infer X)[] ? Task<GetTaskFailure<X>, { [P in keyof T]: GetTaskSuccess<T[P]>; }> : never; type GetEitherFromTask<T> = T extends Task<infer F, infer S> ? Either<F, S> : never; type RemapTasksSeattle<T> = T extends readonly any[] ? Task<never, { [P in keyof T]: GetEitherFromTask<T[P]>; }> : never; /** * The `Task<E, R>` structure represents values that depend on time. This * allows one to model time-based effects explicitly, such that one can have * full knowledge of when they're dealing with delayed computations, latency, * or anything that can not be computed immediately. * * A common use for this structure is to replace the usual Continuation-Passing * Style form of programming, in order to be able to compose and sequence * time-dependent effects using the generic and powerful monadic operations. * * @class * @summary * ((α → Void), (β → Void) → Void)) → Task<E, R> * * Task<E, R> <: Monad[β] * , Functor[β] * , Applicative[β] */ export declare class Task<E, R> { fork: (reject: (err: E) => void, resolve: (x: R) => void) => void; /** * Represents a lazy asyncronous computation a Task * @constructor * @param {(reject: (error: E) => void, resolve: (value: R) => void) => void} fork - Callback with resolvers for failure and success */ constructor(fork: (reject: (err: E) => void, resolve: (x: R) => void) => void); /** * Pointed constructor of a Task similar to Promise.resolve(any) * @param {R} r - value to resolve * @returns {Task<E, R>} the Task */ static of<E, R>(r: R): Task<E, R>; /** * Returns a rejected Task similar to Promise.reject(any) * @param {E} err - Error to reject * @returns {Task<E, R>} the rejected Task */ static rejected<E, R>(err: E): Task<E, R>; /** * Transforms a promise to a Task, take into account that this will run the Promise because of its eager nature * @param {Promise<R>} p - Promise to convert to a Task * @returns {Task<E, R>} the Task from the Promise */ static fromPromise<E, R>(p: Promise<R>): Task<E, R>; /** * Transforms a function that returns a promise to a Task, in this case the promise will be run lazily * @param {() => Promise<R>} p - Promise to convert to a Task * @returns {Task<E, R>} the Task from the Promise */ static fromLazyPromise<E, R>(lazyPromise: () => Promise<R>): Task<E, R>; /** * Applies natural transformation from Either to Task * @param {Either<E, R>} e - Either kind from monet * @returns {Task<E, R>} the Task from the Either provided */ static fromEither<E, R>(e: Either<E, R>): Task<E, R>; /** * Transforms a function that throws to Task * @param {() => R} f - Function that returns R and might throw E * @returns {Task<E, R>} the Task */ static fromTry<E, R>(f: () => R): Task<E, R>; /** * Traverses an array in applicative way transforming every element into a task and running them in parallel * @param {(A) => Task<E, B>} f - Function maps an item to a Task * @param {Array<A>} arr - array of elements to be traversed * @returns {Task<E, Array<B>>} a Task containing an array of transformed elements */ static arrayTraverseA<E, R, R2>(f: (item: R) => Task<E, R2>, arr: R[]): Task<E, R2[]>; /** * Traverses an array in a monadic way transforming every element into a task and running them in sequence * @param {(A) => Task<E, B>} f - Function maps an item to a Task * @param {Array<A>} arr - array of elements to be traversed * @returns {Task<E, Array<B>>} a Task containing an array of transformed elements */ static arrayTraverseM<E, R, R2>(f: (item: R) => Task<E, R2>, arr: R[]): Task<E, R2[]>; /** * Mimics Promise.all() behaviour but runs sequentially a list of Tasks, fails when some one fails * @param {[Task<E, R>, Task<E1, R1>, ... , Task<EN, RN>]} arr - Array of Tasks to traverse * @returns {Task<E | E2 | ... | EN, [R, R1, ... , RN]>} Task of array of resolved Tasks */ static allSeq<T extends readonly any[]>(arr: T): RemapTasks<T>; /** * Mimics Promise.all() behaviour and runs in parallel a list of tasks, fails when some one fails * @param {[Task<E, R>, Task<E1, R1>, ... , Task<EN, RN>]} arr - Array of Tasks to traverse * @returns {Task<E | E2 | ... | EN, [R, R1, ... , RN]>} Task of array of resolved Tasks */ static all<T extends readonly any[]>(arr: T): RemapTasks<T>; /** * Mimics Promise.allSeatle() behaviour and runs sequentially a list of Tasks, never fails * @param {[Task<E, R>, Task<E1, R1>, ... , Task<EN, RN>]} arr - Array of Tasks to traverse * @returns {Task<never, [Either<E, R>, Either<E1, R1>, ... , Either<EN, RN>]>} Task of array of resolved Tasks */ static allSeattleSeq<T extends readonly Task<any, any>[]>(arr: T): RemapTasksSeattle<T>; /** * Mimics Promise.allSeatle() behaviour and runs in parallel a list of Tasks, never fails * @param {[Task<E, R>, Task<E1, R1>, ... , Task<EN, RN>]} arr - Array of Tasks to traverse * @returns {Task<never, [Either<E, R>, Either<E1, R1>, ... , Either<EN, RN>]>} Task of array of resolved Tasks */ static allSeattle<T extends readonly Task<any, any>[]>(arr: T): RemapTasksSeattle<T>; /** * Adapts a function that returns a Task<Error, Success> to bypass Success and continue composition should be use with chain * @param {((input: S) => Task<E, void>) | ((input: S) => void)} f - Function that returns a Task<E, void> * @param {S} success - Success from the previous function * @returns A Task<Error, Success> of the same output Success */ static tap<E, S>(f: ((input: S) => Task<E, void>) | ((input: S) => void)): (i: S) => Task<E, S>; /** * Adapts a function that returns a Task<Error, Success> to bypass error and continue composition should be use with orElse * @param {((input: E) => Task<void, S>) | ((input: E) => void)} f - Function that returns a Task<void, Error> * @param {E} failure - Failure of the previous function * @returns A Task<Error, Success> of the same failure Error */ static rejectTap<E, S>(f: ((input: E) => Task<void, S>) | ((input: E) => void)): (i: E) => Task<E, S>; /** * Applys the successful value of the `Task<E, R>` to the successful * value of the `Task<E, (R → O)>` * @param {Task<E, (r: R) => O>} to - Task holding an `(R → O)` on the success path * @returns {Task<E, O>} the Task with the value applied */ ap<Y>(tf: Task<E, (x: R) => Y>): Task<E, Y>; /** * Applys the successful value of the `Task<E, (R → O)>` to the successful * value of the `Task<E, R>` * @param {Task<E, O>} to - Task holding an `O` on the success path * @returns {Task<E, O>} the Task with the value applied */ apTo<O>(to: Task<E, O>): R extends (arg: O) => any ? Task<E, ReturnType<R>> : never; /** * Applies the function [f] in the success path of resolution of the Task. Functor interface implementation * @param {(r: R) => O} f - Function that transfroms from type R to type O * @returns {Task<E, O>} A Task containing an element of type O */ map<O>(f: (r: R) => O): Task<E, O>; /** * Applies the function [g] in the failure path of resolution of the Task * @param {(e: E) => F} g - Function that transfroms from type E to type F * @returns {Task<F, R>} A Task containing an element of type R but a failure of type F */ rejectMap<F>(g: (e: E) => F): Task<F, R>; /** * Applies the function [f] in the success path of resolution of the Task. Monad interface implementation * @param {(r: R) => Task<E, O>} f - Function that transfroms from type R to type O * @returns {Task<E, O>} A Task containing an element of type O */ chain<O, E2>(f: (r: R) => Task<E2, O>): Task<E | E2, O>; /** * Chain function * @alias chain */ bind: <O, E2>(f: (r: R) => Task<E2, O>) => Task<E | E2, O>; /** * Chain function * @alias chain */ flatMap: <O, E2>(f: (r: R) => Task<E2, O>) => Task<E | E2, O>; /** * Applies the function [g] in the failure path of resolution of the Task * @param {(e: E) => Task<F, R>} g - Function that transfroms from type E to type F * @returns {Task<F, R>} A Task containing an element of type R or failure of type F */ orElse<F, O>(g: (e: E) => Task<F, O>): Task<F, R | O>; /** * Maps over both sides of execution applying [f] over success path or [g] over failure path * @param {(r: R) => Task<E, O>} g - Function that transfroms from type R to type O * @param {(e: E) => Task<F, R>} f - Function that transfroms from type E to type F * @returns A Task containing a failure of type F or a success of type O */ bimap<F, O>(g: (e: E) => F, f: (r: R) => O): Task<F, O>; /** * Catamorphism. Takes two functions [f] and [g], applies the leftmost one to the failure * value, and the rightmost one to the successful value, depending on which one * is present. * @param {(r: R) => Task<E, O>} f - Function that transfroms from type R to type O * @param {(e: E) => Task<F, R>} g - Function that transfroms from type E to type F * @returns A Task containing a failure of type F or a success of type O */ fold<F, O>(g: (e: E) => F, f: (r: R) => O): Task<E, F | O>; /** * Cata function * @alias fold */ cata: <F, O>(g: (e: E) => F, f: (r: R) => O) => Task<E, F | O>; /** * Natural transformation to Promise * You don't know when this could come in handy * @returns {Promise<R>} a Promise equivalent */ toPromise(): Promise<R>; } export {};