diff --git a/src/helpers/fn.test.ts b/src/helpers/fn.test.ts index d5c10e7..fa24b8a 100644 --- a/src/helpers/fn.test.ts +++ b/src/helpers/fn.test.ts @@ -21,4 +21,10 @@ describe.concurrent("asyncFn", () => { const result = await wrappedFn() expect(result.unwrap()).toEqual(42) }) + + it("returns Err result when provided async function returns Err", async () => { + const wrappedFn = asyncFn(async () => Promise.resolve(Err("rekt"))) + const result = await wrappedFn() + expect(result.unwrapErr()).toEqual("rekt") + }) }) diff --git a/src/helpers/fn.ts b/src/helpers/fn.ts index d3024c3..241f679 100644 --- a/src/helpers/fn.ts +++ b/src/helpers/fn.ts @@ -1,4 +1,9 @@ -import type {ResultValueType, ResultErrorType} from "../util" +import type { + ResultValueType, + ResultErrorType, + AsyncResultValueType, + AsyncResultErrorType, +} from "../util" import type {Result} from "../result/interface" import {PromiseResult} from "../result/promise" @@ -9,9 +14,7 @@ export function fn Result>( } export function asyncFn Promise>>(f: T) { - return function ( - ...args: Parameters - ): PromiseResult>, ResultErrorType>> { - return new PromiseResult(f(...args)) + return function (...args: Parameters) { + return new PromiseResult, AsyncResultErrorType>(f(...args)) } } diff --git a/src/helpers/try.ts b/src/helpers/try.ts index ded9842..be5b14b 100644 --- a/src/helpers/try.ts +++ b/src/helpers/try.ts @@ -1,5 +1,5 @@ import {Panic} from "../error/panic" -import {type ErrorHandler, type ResultError, type StdError, toStdError} from "../error/result_error" +import {type ErrorHandler, type ResultError, StdError, toStdError} from "../error/result_error" import {Err} from "../result/err" import type {Result} from "../result/interface" import {Ok} from "../result/ok" @@ -35,7 +35,7 @@ export function tryFnWith( } export function tryPromise(promise: Promise): PromiseResult { - return new PromiseResult( + return new PromiseResult( promise.then( (value) => Ok(value), (error: unknown) => Err(toStdError(error)), diff --git a/src/option/interface.ts b/src/option/interface.ts index f25ddf5..15cd22a 100644 --- a/src/option/interface.ts +++ b/src/option/interface.ts @@ -31,4 +31,17 @@ export interface OptionMethods { toJSON(): {meta: "Some"; data: T} | {meta: "None"} } -export type Option = Some | None +export interface SomeVariant { + readonly some: true + readonly none: false + readonly value: T +} + +export interface NoneVariant { + readonly some: false + readonly none: true +} + +export type OptionVariants = SomeVariant | NoneVariant + +export type Option = OptionVariants & OptionMethods diff --git a/src/option/none.ts b/src/option/none.ts index 6a4df12..7a8ae76 100644 --- a/src/option/none.ts +++ b/src/option/none.ts @@ -1,9 +1,9 @@ import {Panic, UnwrapPanic} from "../error/panic" import {inspectSymbol} from "../util" -import type {OptionMethods, Option} from "./interface" +import type {OptionMethods, Option, NoneVariant} from "./interface" import type {Some} from "./some" -export class NoneImpl implements OptionMethods { +export class NoneImpl implements NoneVariant, OptionMethods { readonly some = false readonly none = true diff --git a/src/option/promise.test.ts b/src/option/promise.test.ts index 8574c1a..b14ab35 100644 --- a/src/option/promise.test.ts +++ b/src/option/promise.test.ts @@ -2,7 +2,7 @@ import {describe, it, expect, vi} from "vitest" import {Panic, UnwrapPanic, PromiseOption, Some, None} from ".." function promiseSome(value: T) { - return new PromiseOption(Promise.resolve(Some(value))) + return new PromiseOption(Promise.resolve(Some(value))) } function promiseNone() { diff --git a/src/option/some.ts b/src/option/some.ts index 35da0c3..f7a9546 100644 --- a/src/option/some.ts +++ b/src/option/some.ts @@ -1,9 +1,9 @@ import type {Panic} from "../error/panic" import {inspectSymbol} from "../util" -import type {OptionMethods, Option} from "./interface" +import type {OptionMethods, Option, SomeVariant} from "./interface" import {None} from "./none" -export class SomeImpl implements OptionMethods { +export class SomeImpl implements SomeVariant, OptionMethods { readonly some = true readonly none = false readonly value: T diff --git a/src/result/err.ts b/src/result/err.ts index 0423f28..ee59f4a 100644 --- a/src/result/err.ts +++ b/src/result/err.ts @@ -1,11 +1,10 @@ import {Panic, UnwrapPanic} from "../error/panic" import {inspectSymbol} from "../util" -import type {Result, ResultMethods} from "./interface" +import type {ErrVariant, Result, ResultMethods} from "./interface" import type {Ok} from "./ok" -export class ErrImpl implements ResultMethods { +export class ErrImpl implements ErrVariant, ResultMethods { readonly ok = false - readonly value?: never readonly err = true readonly error: E diff --git a/src/result/interface.ts b/src/result/interface.ts index 6916801..4d36666 100644 --- a/src/result/interface.ts +++ b/src/result/interface.ts @@ -34,4 +34,18 @@ export interface ResultMethods { toJSON(): {meta: "Ok"; data: T} | {meta: "Err"; data: E} } -export type Result = Ok | Err +export interface OkVariant { + readonly ok: true + readonly err: false + readonly value: T +} + +export interface ErrVariant { + readonly ok: false + readonly err: true + readonly error: E +} + +export type ResultVariants = OkVariant | ErrVariant + +export type Result = ResultVariants & ResultMethods diff --git a/src/result/ok.ts b/src/result/ok.ts index 74bb70d..55c6cac 100644 --- a/src/result/ok.ts +++ b/src/result/ok.ts @@ -1,13 +1,12 @@ import {Panic, UnwrapPanic} from "../error/panic" import {inspectSymbol} from "../util" import type {Err} from "./err" -import type {Result, ResultMethods} from "./interface" +import type {OkVariant, Result, ResultMethods} from "./interface" -export class OkImpl implements ResultMethods { +export class OkImpl implements OkVariant, ResultMethods { readonly ok = true - readonly value: T readonly err = false - readonly error?: never + readonly value: T constructor(value: T) { this.value = value diff --git a/src/util.ts b/src/util.ts index 511dd73..4d7548e 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,28 +1,20 @@ -import type {Option} from "./option/interface" -import type {PromiseOption} from "./option/promise" -import type {Result} from "./result/interface" -import type {PromiseResult} from "./result/promise" +import type {Err} from "./result/err" +import type {Ok} from "./result/ok" export const inspectSymbol = Symbol.for("nodejs.util.inspect.custom") -export type ResultValueErrorType = T extends - | Result - | PromiseResult - | Promise> - | ((...args: any[]) => Result) - | ((...args: any[]) => PromiseResult) - | ((...args: any[]) => Promise>) +export type ResultValueErrorType = T extends (...args: any[]) => Ok | Err ? {value: V; error: E} : never + export type ResultValueType = ResultValueErrorType["value"] export type ResultErrorType = ResultValueErrorType["error"] -export type OptionValueType = T extends - | Option - | PromiseOption - | Promise> - | ((...args: any[]) => Option) - | ((...args: any[]) => PromiseOption) - | ((...args: any[]) => Promise>) - ? V +export type AsyncResultValueErrorType = T extends ( + ...args: any[] +) => Promise | Err> + ? {value: V; error: E} : never + +export type AsyncResultValueType = AsyncResultValueErrorType["value"] +export type AsyncResultErrorType = AsyncResultValueErrorType["error"]