Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add variants #9

Merged
merged 7 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/helpers/fn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
})
})
13 changes: 8 additions & 5 deletions src/helpers/fn.ts
Original file line number Diff line number Diff line change
@@ -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"

Expand All @@ -9,9 +14,7 @@ export function fn<T extends (...args: any[]) => Result<any, any>>(
}

export function asyncFn<T extends (...args: any[]) => Promise<Result<any, any>>>(f: T) {
return function (
...args: Parameters<T>
): PromiseResult<ResultValueType<ReturnType<T>>, ResultErrorType<ReturnType<T>>> {
return new PromiseResult(f(...args))
return function (...args: Parameters<T>) {
return new PromiseResult<AsyncResultValueType<T>, AsyncResultErrorType<T>>(f(...args))
}
}
4 changes: 2 additions & 2 deletions src/helpers/try.ts
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -35,7 +35,7 @@ export function tryFnWith<T, E extends ResultError>(
}

export function tryPromise<T>(promise: Promise<T>): PromiseResult<T, StdError> {
return new PromiseResult(
return new PromiseResult<T, StdError>(
promise.then(
(value) => Ok(value),
(error: unknown) => Err(toStdError(error)),
Expand Down
15 changes: 14 additions & 1 deletion src/option/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,17 @@ export interface OptionMethods<T> {
toJSON(): {meta: "Some"; data: T} | {meta: "None"}
}

export type Option<T> = Some<T> | None
export interface SomeVariant<T> {
readonly some: true
readonly none: false
readonly value: T
}

export interface NoneVariant {
readonly some: false
readonly none: true
}

export type OptionVariants<T> = SomeVariant<T> | NoneVariant

export type Option<T> = OptionVariants<T> & OptionMethods<T>
4 changes: 2 additions & 2 deletions src/option/none.ts
Original file line number Diff line number Diff line change
@@ -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<never> {
export class NoneImpl implements NoneVariant, OptionMethods<never> {
readonly some = false
readonly none = true

Expand Down
2 changes: 1 addition & 1 deletion src/option/promise.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {describe, it, expect, vi} from "vitest"
import {Panic, UnwrapPanic, PromiseOption, Some, None} from ".."

function promiseSome<T>(value: T) {
return new PromiseOption(Promise.resolve(Some<T>(value)))
return new PromiseOption<T>(Promise.resolve(Some<T>(value)))
}

function promiseNone() {
Expand Down
4 changes: 2 additions & 2 deletions src/option/some.ts
Original file line number Diff line number Diff line change
@@ -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<T> implements OptionMethods<T> {
export class SomeImpl<T> implements SomeVariant<T>, OptionMethods<T> {
readonly some = true
readonly none = false
readonly value: T
Expand Down
5 changes: 2 additions & 3 deletions src/result/err.ts
Original file line number Diff line number Diff line change
@@ -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<E> implements ResultMethods<never, E> {
export class ErrImpl<E> implements ErrVariant<E>, ResultMethods<never, E> {
readonly ok = false
readonly value?: never
readonly err = true
readonly error: E

Expand Down
16 changes: 15 additions & 1 deletion src/result/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,18 @@ export interface ResultMethods<T, E> {
toJSON(): {meta: "Ok"; data: T} | {meta: "Err"; data: E}
}

export type Result<T, E> = Ok<T> | Err<E>
export interface OkVariant<T> {
readonly ok: true
readonly err: false
readonly value: T
}

export interface ErrVariant<E> {
readonly ok: false
readonly err: true
readonly error: E
}

export type ResultVariants<T, E> = OkVariant<T> | ErrVariant<E>

export type Result<T, E> = ResultVariants<T, E> & ResultMethods<T, E>
7 changes: 3 additions & 4 deletions src/result/ok.ts
Original file line number Diff line number Diff line change
@@ -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<T> implements ResultMethods<T, never> {
export class OkImpl<T> implements OkVariant<T>, ResultMethods<T, never> {
readonly ok = true
readonly value: T
readonly err = false
readonly error?: never
readonly value: T

constructor(value: T) {
this.value = value
Expand Down
30 changes: 11 additions & 19 deletions src/util.ts
Original file line number Diff line number Diff line change
@@ -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> = T extends
| Result<infer V, infer E>
| PromiseResult<infer V, infer E>
| Promise<Result<infer V, infer E>>
| ((...args: any[]) => Result<infer V, infer E>)
| ((...args: any[]) => PromiseResult<infer V, infer E>)
| ((...args: any[]) => Promise<Result<infer V, infer E>>)
export type ResultValueErrorType<T> = T extends (...args: any[]) => Ok<infer V> | Err<infer E>
? {value: V; error: E}
: never

export type ResultValueType<T> = ResultValueErrorType<T>["value"]
export type ResultErrorType<T> = ResultValueErrorType<T>["error"]

export type OptionValueType<T> = T extends
| Option<infer V>
| PromiseOption<infer V>
| Promise<Option<infer V>>
| ((...args: any[]) => Option<infer V>)
| ((...args: any[]) => PromiseOption<infer V>)
| ((...args: any[]) => Promise<Option<infer V>>)
? V
export type AsyncResultValueErrorType<T> = T extends (
...args: any[]
) => Promise<Ok<infer V> | Err<infer E>>
? {value: V; error: E}
: never

export type AsyncResultValueType<T> = AsyncResultValueErrorType<T>["value"]
export type AsyncResultErrorType<T> = AsyncResultValueErrorType<T>["error"]