Result
Typed success/failure values and optional values without exceptions.
@ozaco/std/resultA Result<T, E> is either a Success<T> carrying a value or a Failure<E> carrying an error, message and a list of causes. A Maybe<T> models presence (Just) or absence (Nothing).
Every constructor transparently handles promises: pass a PromiseLike and you get back a Result.Async<T, E> (a Promise<Result<T, E>>), so the same helpers work for sync and async code.
Both Result and Maybe are plain objects tagged with a registered Symbol, and Result is iterable — enabling generator-style yield* unwrapping.
Constructors
Build results and optional values.
succeed
Wrap a value in a `Success`. Awaits promises into a `Result.Async`.
function succeed(): Result<void, never>
function succeed<const T>(value: T): Result.For<T, Awaited<T>, never>import { succeed } from '@ozaco/std/result'
const ok = succeed(42) //=> Success<number>
const unit = succeed() //=> Success<void>
const later = succeed(fetchUser()) //=> Result.Async<User, never>fail
Wrap an error in a `Failure`, optionally with a message and causes.
function fail(): Result<never, void>
function fail<const E>(
error: E,
message?: string,
...causes: string[]
): Result.For<E, never, Awaited<E>>import { fail } from '@ozaco/std/result'
const err = fail(new Error('boom'), 'while parsing', 'config.load')
//=> Failure<Error> { message: 'while parsing', causes: ['config.load'] }just
Wrap a value in a `Maybe.Just`.
function just(): Maybe<void>
function just<T>(value?: T): Maybe<T>import { just } from '@ozaco/std/result'
const present = just('token') //=> Just<string>nothing
Create an empty `Maybe.Nothing`.
function nothing<T = void>(): Maybe<T>import { nothing } from '@ozaco/std/result'
const absent = nothing<string>() //=> Nothing<string>Guards
Narrow unknown values with type predicates.
isSuccess
Narrow a value to `Result.Success`.
function isSuccess(value: unknown): value is Result.Success<unknown>isFailure
Narrow a value to `Result.Failure`.
function isFailure(value: unknown): value is Result.Failure<unknown>isResult
Narrow a value to any `Result`.
function isResult(value: unknown): value is Result<unknown, unknown>isJust
Narrow a value to `Maybe.Just`.
function isJust(value: unknown): value is Maybe.Just<unknown>isNothing
Narrow a value to `Maybe.Nothing`.
function isNothing(value: unknown): value is Maybe.Nothing<unknown>isMaybe
Narrow a value to any `Maybe`.
function isMaybe(value: unknown): value is Maybe<unknown>Combinators
Normalize, unwrap and adapt results.
auto
Coerce any value into a `Result`, passing existing results through.
function auto<R extends Result.Both<any, any>>(result: R): /* normalized */ Result<...>
function auto<R extends Result.Both<any, any>, T>(result: R, defaultValue: T): Result<...>
function auto<const T>(value: T): Result.ResultFromUnion<T>Existing results are returned untouched; plain values are wrapped in succeed. When a defaultValue is given, a failure is replaced by auto(defaultValue). Promises resolve first, yielding a Result.Async.
import { auto } from '@ozaco/std/result'
auto(42) //=> Success<number>
auto(someResult) //=> someResult, unchanged
auto(mightFail, 'fallback') //=> Success<'fallback'> if it failedunwrap
Extract the success value, or throw / return a default on failure.
function unwrap<R extends Result.Both<any, any>>(result: R): Result.InferSuccess<R>
function unwrap<R extends Result.Both<any, any>, T>(
result: R,
defaultValue: T,
): Result.InferSuccess<R> | TWithout a default, a failure is thrown (the Failure object itself). With a default, the default is returned instead. Async results unwrap to a Promise.
import { succeed, fail, unwrap } from '@ozaco/std/result'
unwrap(succeed(42)) //=> 42
unwrap(fail('x'), 0) //=> 0
unwrap(fail('x')) // throws the Failurethrowable
Run a callback and capture thrown errors as a `Failure`.
function throwable<R, E extends Result.ErrorConstructor>(
cb: () => R,
errorClass?: E,
...causes: string[]
): Result.ResultFromUnion<R | Result.Failure<E['prototype']>>Wraps cb in a try/catch. A thrown value is normalized into fail(...); if errorClass is provided and the thrown value is not an instance of it, it is wrapped via new errorClass(error). Async callbacks are handled too.
import { throwable } from '@ozaco/std/result'
const parsed = throwable(() => JSON.parse(input))
//=> Success<unknown> | Failure<Error>asFailure
Coerce any error into a `Failure`, optionally appending a cause.
function asFailure<E>(error: Result.Failure<E>, cause?: string): Result.Failure<E>
function asFailure(error: unknown, cause?: string): Result.Failure<unknown>appendCauses
Push extra cause strings onto a failure, leaving successes untouched.
function appendCauses<T extends Result.Both<any, any>>(
result: T,
...causes: string[]
): TTypes
Result
A success or failure value: `Result.Success<T> | Result.Failure<E>`.
type Result<T, E> = Result.Success<T> | Result.Failure<E>The Result namespace also exposes:
- •
Success<T>—{ value: T }, iterable, yielding the value. - •
Failure<E>—{ error: E, message: string, causes: string[] }, iterable. - •
Async<T, E>—Promise<Result<T, E>>. - •
Both<T, E>—Result.Async<T, E> | Result<T, E>. - •
InferSuccess<T>/InferFailure<T>— extract the value/error type from a result or a function returning one.
Maybe
An optional value: `Maybe.Just<T> | Maybe.Nothing<T>`.
type Maybe<T> = Maybe.Just<T> | Maybe.Nothing<T>Maybe.Just<T> is { value: T }; Maybe.Nothing<T> carries no value. Both are tagged with the corresponding registered symbol.
Constants
Registered symbols used as discriminant tags.
RESULT_SUCCESS
Tag for `Result.Success`.
const RESULT_SUCCESS: unique symbol // Symbol.for('std:result:success')RESULT_FAILURE
Tag for `Result.Failure`.
const RESULT_FAILURE: unique symbol // Symbol.for('std:result:failure')MAYBE_JUST
Tag for `Maybe.Just`.
const MAYBE_JUST: unique symbol // Symbol.for('std:result:just')MAYBE_NOTHING
Tag for `Maybe.Nothing`.
const MAYBE_NOTHING: unique symbol // Symbol.for('std:result:nothing')