Skip to content

Commit

Permalink
combineAsync
Browse files Browse the repository at this point in the history
  • Loading branch information
adjsky committed Mar 10, 2024
1 parent 2aaca5b commit d2ca96a
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 5 deletions.
13 changes: 13 additions & 0 deletions packages/resulto/src/result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -820,3 +820,16 @@ export function combine<T extends Result<unknown, unknown>[]>(

return ok(unwrapped)
}

/**
* Accepts an array of `Results` and `AsyncResults` and returns an `AsyncResult`.
*
* If each `Result` and `AsyncResult` in the provided array is `Ok`, then the
* returned `AsyncResult` will contain an array of `Ok` values, otherwise the
* returned `AsyncResult` will contain the first `Err` error.
*/
export function combineAsync<
T extends (Result<unknown, unknown> | AsyncResult<unknown, unknown>)[]
>(results: T): AsyncResult<UnwrapOks<T>, UnwrapErrs<T>[number]> {
return chain(Promise.all(results).then(combine))
}
22 changes: 17 additions & 5 deletions packages/resulto/src/utility.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Result } from "./result"
import type { AsyncResult, Result } from "./result"

export type Predicate<T> = (value: T) => boolean

Expand All @@ -8,12 +8,24 @@ export type Fn<T, U> = (value: T) => U

export type ErrFn<E, F> = (error: E) => F

export type UnwrapOks<T extends Result<unknown, unknown>[]> = {
[i in keyof T]: T[i] extends Result<infer U, unknown> ? U : never
export type UnwrapOks<
T extends (Result<unknown, unknown> | AsyncResult<unknown, unknown>)[]
> = {
[i in keyof T]: T[i] extends Result<infer U, unknown>
? U
: T[i] extends AsyncResult<infer U, unknown>
? U
: never
}

export type UnwrapErrs<T extends Result<unknown, unknown>[]> = {
[i in keyof T]: T[i] extends Result<unknown, infer U> ? U : never
export type UnwrapErrs<
T extends (Result<unknown, unknown> | AsyncResult<unknown, unknown>)[]
> = {
[i in keyof T]: T[i] extends Result<unknown, infer U>
? U
: T[i] extends AsyncResult<unknown, infer U>
? U
: never
}

export class ResultError extends Error {
Expand Down
28 changes: 28 additions & 0 deletions packages/resulto/test/result-async.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, expect, test, vi } from "vitest"

import { err, errAsync, fromPromise, ok, okAsync } from "../src"
import { combineAsync } from "../src/result"

describe("utils", () => {
test("okAsync", async () => {
Expand Down Expand Up @@ -37,6 +38,33 @@ describe("utils", () => {
).toBe("mapped error")
})
})

describe("combineAsync", () => {
test("single `Ok`", async () => {
expect(await combineAsync([ok(4)]).unwrap()).toEqual([4])
})

test("multiple `Ok`s", async () => {
expect(await combineAsync([ok(4), okAsync("ook")]).unwrap()).toEqual([
4,
"ook"
])
})

test("single `Err`", async () => {
expect(await combineAsync([err("err")]).unwrapErr()).toBe("err")
})

test("multiple `Err`s", async () => {
expect(await combineAsync([err("1"), errAsync("2")]).unwrapErr()).toBe(
"1"
)
})

test("`Ok` + `Err`", async () => {
expect(await combineAsync([okAsync(1), err(2)]).unwrapErr()).toBe(2)
})
})
})

describe("Result.asyncMap", () => {
Expand Down

0 comments on commit d2ca96a

Please sign in to comment.