data.task.ts
Version:
Personal functional Task typeclass implementation
202 lines (201 loc) • 10.1 kB
TypeScript
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 {};