Skip to content

Commit

Permalink
infer combine return value as a tuple (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
adjsky authored Mar 19, 2024
1 parent 81a58a7 commit f11d821
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 8 deletions.
14 changes: 9 additions & 5 deletions packages/resulto/src/result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
type ErrFn,
type ErrPredicate,
type Fn,
Mutable,
type Predicate,
ResultError,
type UnwrapErrs,
Expand Down Expand Up @@ -805,10 +806,10 @@ export function fromThrowable<T, E>(
* will contain an array of `Ok` values, otherwise the returned `Result` will
* contain the first `Err` error.
*/
export function combine<T extends Result<unknown, unknown>[]>(
results: T
export function combine<T extends readonly Result<unknown, unknown>[]>(
results: [...T]
): Result<UnwrapOks<T>, UnwrapErrs<T>[number]> {
const unwrapped = [] as UnwrapOks<T>
const unwrapped = [] as Mutable<UnwrapOks<T>>

for (const result of results) {
if (result.isErr()) {
Expand All @@ -829,7 +830,10 @@ export function combine<T extends Result<unknown, unknown>[]>(
* 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]> {
T extends readonly (
| Result<unknown, unknown>
| AsyncResult<unknown, unknown>
)[]
>(results: [...T]): AsyncResult<UnwrapOks<T>, UnwrapErrs<T>[number]> {
return chain(Promise.all(results).then(combine))
}
14 changes: 12 additions & 2 deletions packages/resulto/src/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ export type Fn<T, U> = (value: T) => U
export type ErrFn<E, F> = (error: E) => F

export type UnwrapOks<
T extends (Result<unknown, unknown> | AsyncResult<unknown, unknown>)[]
T extends readonly (
| Result<unknown, unknown>
| AsyncResult<unknown, unknown>
)[]
> = {
[i in keyof T]: T[i] extends Result<infer U, unknown>
? U
Expand All @@ -19,7 +22,10 @@ export type UnwrapOks<
}

export type UnwrapErrs<
T extends (Result<unknown, unknown> | AsyncResult<unknown, unknown>)[]
T extends readonly (
| Result<unknown, unknown>
| AsyncResult<unknown, unknown>
)[]
> = {
[i in keyof T]: T[i] extends Result<unknown, infer U>
? U
Expand All @@ -28,6 +34,10 @@ export type UnwrapErrs<
: never
}

export type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}

export class ResultError extends Error {
data: unknown

Expand Down
19 changes: 18 additions & 1 deletion packages/resulto/test/result.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { assertType, describe, test } from "vitest"

import { err, ok } from "../src"
import { combine, err, ok } from "../src"
import { combineAsync } from "../src/result"

describe(".value, .error", () => {
const value = 4
Expand Down Expand Up @@ -33,3 +34,19 @@ describe(".value, .error", () => {
assertType<string>(errResult.error)
})
})

describe("combine/combineAsync", () => {
test("infers Ok values", () => {
{
const res1 = ok([4])
const res2 = ok("")

assertType<[number[], string]>(combine([res1, res2]).unwrap())
assertType<Promise<[number[], string]>>(
combineAsync([res1, res2]).unwrap()
)
}

assertType<[number, string]>(combine([ok(4), ok("")]).unwrap())
})
})

0 comments on commit f11d821

Please sign in to comment.