diff --git a/docs/task-static.md b/docs/task-static.md index e2afafca..fd99b4bc 100644 --- a/docs/task-static.md +++ b/docs/task-static.md @@ -260,6 +260,30 @@ type fromPromise = (maybePromise: S | Promise) => Task {% endtab %} {% endtabs %} +## fromPromises + +Converts an array of Promises into an array of Tasks and joins them with Task.all + +Promise's do not track an error type (one of the reasons Tasks are more powerful) so the resulting Task is unable to infer the error type as well. It is recommended to pass it in as a generic. + +{% tabs %} +{% tab title="Usage" %} + +```typescript +const task: Task = Task.fromPromises(fetch(URL)) +``` + +{% endtab %} + +{% tab title="Type Definition" %} + +```typescript +type fromPromises = (promises: Array>) => Task +``` + +{% endtab %} +{% endtabs %} + ## fromLazyPromise Given a function which returns a Promise, turn that into a Task. This allows the Promise not to start until the Task forks (following the lazy philosophy of the rest of the library). This also means if two tasks chain from this one, the promise creating function will be called twice. See `onlyOnce` if you wish to avoid this. diff --git a/src/Task/Task.ts b/src/Task/Task.ts index 523900b6..66460385 100644 --- a/src/Task/Task.ts +++ b/src/Task/Task.ts @@ -211,6 +211,14 @@ export const fromPromise = ( ? new Task((reject, resolve) => maybePromise.then(resolve, reject)) : of(maybePromise) +/** + * Given an array of promises, create a Task which relies on it. + * @param promise The promises we will gather the success from. + */ +export const fromPromises = ( + promises: Array>, +): Task => all(promises.map(fromPromise)) + /** * Take a function which generates a promise and lazily execute it. * @param getPromise The getter function @@ -690,6 +698,7 @@ export class Task implements PromiseLike { public static firstSuccess = firstSuccess public static never = never public static fromPromise = fromPromise + public static fromPromises = fromPromises public static fromLazyPromise = fromLazyPromise public static race = race public static external = external @@ -756,7 +765,7 @@ export class Task implements PromiseLike { return this.toPromise().then(onfulfilled, onrejected) } - public chain(fn: (result: S) => Task): Task { + public chain(fn: (result: S) => Task): Task { return chain(fn, this) } diff --git a/src/Task/__tests__/fromPromises.spec.ts b/src/Task/__tests__/fromPromises.spec.ts new file mode 100644 index 00000000..63f9e201 --- /dev/null +++ b/src/Task/__tests__/fromPromises.spec.ts @@ -0,0 +1,36 @@ +import { fromPromises } from "../Task" +import { ERROR_RESULT, SUCCESS_RESULT } from "./util" + +describe("fromPromisea", () => { + test("should succeed when all promises succeeds", async () => { + const resolve = jest.fn() + const reject = jest.fn() + + const promiseA = Promise.resolve(SUCCESS_RESULT) + const promiseB = Promise.resolve(SUCCESS_RESULT) + + fromPromises([promiseA, promiseB]).fork(reject, resolve) + + await promiseA.catch(() => void 0) + await promiseB.catch(() => void 0) + + expect(resolve).toBeCalledWith([SUCCESS_RESULT, SUCCESS_RESULT]) + expect(reject).not.toBeCalled() + }) + + test("should fail when a promise fails", async () => { + const resolve = jest.fn() + const reject = jest.fn() + + const promiseA = Promise.resolve(SUCCESS_RESULT) + const promiseB = Promise.reject(ERROR_RESULT) + + fromPromises([promiseA, promiseB]).fork(reject, resolve) + + await promiseA.catch(() => void 0) + await promiseB.catch(() => void 0) + + expect(resolve).not.toBeCalled() + expect(reject).toBeCalledWith(ERROR_RESULT) + }) +})