Skip to content

Commit

Permalink
Add test case
Browse files Browse the repository at this point in the history
  • Loading branch information
bkiac committed Apr 3, 2024
1 parent e5531aa commit d2b7a70
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 4 deletions.
4 changes: 3 additions & 1 deletion src/result_promise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ export class ResultPromise<T, E> implements PromiseLike<Result<T, E>> {
/**
* Async version of `Result#andThenAsync`.
*/
andThenAsync<U, F>(f: (value: T) => Promise<Result<U, F>>): ResultPromise<U, E | F> {
andThenAsync<U, F>(
f: (value: T) => ResultPromise<U, F> | Promise<Result<U, F>>,
): ResultPromise<U, E | F> {
return new ResultPromise(this.then((result) => result.andThenAsync((value) => f(value))))
}

Expand Down
17 changes: 15 additions & 2 deletions test/result.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {describe, it, expect, expectTypeOf, vi} from "vitest"
import {Panic, Ok, Err, Result, Some, None, ErrorWithTag} from "../src"
import {test} from "vitest"
import {Panic, Ok, Err, Result, Some, None, ErrorWithTag, ResultPromise} from "../src"

export function TestOk<T, E>(value: T): Result<T, E> {
return Ok(value)
Expand Down Expand Up @@ -148,6 +147,20 @@ describe.concurrent("andThenAsync", () => {
a.unwrapErr(),
)
})

it("can map error type", async () => {
const a = TestErr<number, "foo">("foo")
const b = a.andThenAsync(async (value) => {
if (value < 0) {
return Err("bar" as const)
}
if (value > 1) {
return Ok(value)
}
return Err("baz" as const)
})
expectTypeOf(b).toEqualTypeOf<ResultPromise<number, "foo" | "bar" | "baz">>()
})
})

describe.concurrent("expect", () => {
Expand Down
72 changes: 71 additions & 1 deletion test/result_promise.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import {describe, it, expect, expectTypeOf} from "vitest"
import {Err, Panic, ResultPromise, Ok, Result, ErrorWithTag, Some, None} from "../src"
import {
Err,
Panic,
ResultPromise,
Ok,
Result,
ErrorWithTag,
Some,
None,
CaughtError,
tryPromise,
} from "../src"
import {TestErr, TestOk} from "./result.test"
import {vi} from "vitest"

Expand Down Expand Up @@ -73,6 +84,65 @@ describe.concurrent("andThenAsync", () => {
const a = TestErrPromise<number, string>(0)
await expect(a.andThenAsync(async (value) => Ok(value + 1)).unwrapErr()).resolves.toEqual(0)
})

it("can map error type", async () => {
const a = TestErrPromise<"foo", number>("foo")
const b = a.andThenAsync(async (value) => {
if (value < 0) {
return Err("bar" as const)
}
if (value > 1) {
return Ok(value)
}
return Err("baz" as const)
})
expectTypeOf(b).toEqualTypeOf<ResultPromise<number, "foo" | "bar" | "baz">>()
})

it("can map error type with complicated error", async () => {
class PrismaError extends ErrorWithTag {
readonly tag = "prisma"
// readonly message = "Prisma error"

// constructor(public readonly error: CaughtError) {
// super()
// }
}

abstract class NotFoundError extends ErrorWithTag {
// category = "not_found"
}

class AccountNotFoundError extends NotFoundError {
readonly tag = "account"
// readonly message = "Account not found"
}

async function fn(): Promise<{id: number} | null> {
return {id: 1}
}

const maybeExpiredToken = await tryPromise(fn())
.mapErr((error) => new PrismaError(error))

Check failure on line 126 in test/result_promise.test.ts

View workflow job for this annotation

GitHub Actions / test-node

No overload matches this call.
.andThen((maybeAccount) => {
if (maybeAccount) {
return Ok(maybeAccount)
}
return Err(new AccountNotFoundError())
})
.andThenAsync(async (account) => {

Check failure on line 133 in test/result_promise.test.ts

View workflow job for this annotation

GitHub Actions / test-node

Argument of type '(account: { id: number; }) => Promise<Ok<{ id: number; }, never> | Err<AccountNotFoundError, never> | Err<PrismaError, never>>' is not assignable to parameter of type '(value: { id: number; }) => ResultPromise<{ id: number; }, AccountNotFoundError> | Promise<Result<{ id: number; }, AccountNotFoundError>>'.
if (account.id < 0) {
return Err(new AccountNotFoundError())
}

const ye = await tryPromise(fn()).mapErr((error) => new PrismaError(error))

Check failure on line 138 in test/result_promise.test.ts

View workflow job for this annotation

GitHub Actions / test-node

No overload matches this call.
if (ye.isErr) {
return Err(ye.value)
}

return Ok(account)
})
})
})

describe.concurrent("expect", () => {
Expand Down

0 comments on commit d2b7a70

Please sign in to comment.