Skip to main content

Result API Documentation

Package: @alt-stack/result

All failures are constrained by ResultError: an Error instance with a string _tag. The declared property is readonly, although TypeScript also allows a mutable string property to satisfy that structural constraint. Give _tag a readonly literal type (as const or an equivalent declaration) when you want precise, exhaustive narrowing.

Core types

Result<A, E>

type Result<A, E extends ResultError = never> = Ok<A> | Err<E>;

A is the success value and E is the union of expected tagged errors. With the default E = never, a result cannot contain a representable Err.

Ok<A>

PropertyTypeMeaning
_tag"Ok"outer discriminant
valueAsuccess value

Both properties are readonly.

Err<E>

PropertyTypeMeaning
_tag"Err"outer discriminant
errorEtagged Error instance

Both properties are readonly.

ResultError

type ResultError = Error & { readonly _tag: string };

This is the compile-time constraint. Because TypeScript's structural assignability permits a mutable property where a readonly property is expected, neither readonly nor a literal type is required for conformance. At runtime, isResultError and assertResultError check only that the value is an Error and _tag is a string.

TaggedError<Tag>

abstract class TaggedError<Tag extends string = string> extends Error {
abstract readonly _tag: [string] extends [Tag]
? string
: StringLiteral<Tag>;
constructor(message: string);
}

StringLiteral is an internal, non-exported helper that rejects the wide string type. With the default Tag = string, the conditional property type resolves to string. TypeScript does not infer a superclass type argument from the subclass's _tag declaration, so supply the generic explicitly when the base class should enforce one exact tag.

Subclasses provide _tag. The base constructor installs a name getter that returns _tag, or "Error" before the subclass field has initialized.

class ConflictError extends TaggedError<"ConflictError"> {
readonly _tag = "ConflictError" as const;

constructor(readonly key: string) {
super(`Conflict on ${key}`);
}
}

Constructors

ok

function ok(): Ok<void>;
function ok<A>(value: A): Ok<A>;

Creates an Ok. Calling it with no argument stores undefined as the void value.

err

function err<E extends ResultError>(error: E): Err<E>;

Creates an Err without cloning or wrapping error.

Guards

isOk

function isOk<A, E extends ResultError>(result: Result<A, E>): result is Ok<A>;

Returns whether the outer _tag is "Ok" and narrows result.

isErr

function isErr<A, E extends ResultError>(result: Result<A, E>): result is Err<E>;

Returns whether the outer _tag is "Err" and narrows result.

Transformations

map

function map<A, E extends ResultError, B>(
result: Result<A, E>,
fn: (value: A) => B,
): Result<B, E>;

Runs fn for Ok and passes an Err through unchanged. Exceptions thrown by fn are not caught.

flatMap

function flatMap<A, E extends ResultError, B, E2 extends ResultError>(
result: Result<A, E>,
fn: (value: A) => Result<B, E2>,
): Result<B, E | E2>;

Chains a result-returning function and unions the original and callback error types. An existing Err short-circuits.

mapError

function mapError<A, E extends ResultError, E2 extends ResultError>(
result: Result<A, E>,
fn: (error: E) => E2,
): Result<A, E2>;

Transforms only the error. fn must return another ResultError.

catchError

function catchError<
A,
E extends ResultError,
B,
E2 extends ResultError,
>(
result: Result<A, E>,
fn: (error: E) => Result<B, E2>,
): Result<A | B, E2>;

Handles the original E. The returned success type includes the original and fallback values; the returned failure type is only the fallback's E2.

Extraction

unwrap

function unwrap<A, E extends ResultError>(result: Result<A, E>): A;

Returns the Ok value. For Err, throws the original error instance with its original stack.

unwrapOr

function unwrapOr<A, E extends ResultError>(
result: Result<A, E>,
defaultValue: A,
): A;

Returns defaultValue for Err.

unwrapOrElse

function unwrapOrElse<A, E extends ResultError>(
result: Result<A, E>,
fn: (error: E) => A,
): A;

Computes a default from the error. fn is not called for Ok.

getOrUndefined

function getOrUndefined<A, E extends ResultError>(
result: Result<A, E>,
): A | undefined;

Returns the success value or undefined. It cannot distinguish ok(undefined) from an Err after extraction.

getErrorOrUndefined

function getErrorOrUndefined<A, E extends ResultError>(
result: Result<A, E>,
): E | undefined;

Returns the error or undefined.

Pattern matching

match

function match<A, E extends ResultError, B, C = B>(
result: Result<A, E>,
handlers: {
ok: (value: A) => B;
err: (error: E) => C;
},
): B | C;

Calls exactly one named handler. The handlers may return different types.

fold

function fold<A, E extends ResultError, B>(
result: Result<A, E>,
onErr: (error: E) => B,
onOk: (value: A) => B,
): B;

Reduces either branch to the same output type. Note the positional order: error handler first, success handler second.

Async boundaries

ResultAsync<A, E>

type ResultAsync<A, E extends ResultError> = Promise<Result<A, E>>;

This is a type alias, not a lazy wrapper or a class with methods.

fromPromise

function fromPromise<A, E extends ResultError>(
promise: Promise<A>,
onReject: (error: unknown) => E,
): ResultAsync<A, E>;

Converts fulfillment to Ok and rejection to Err(onReject(error)). It does not inspect fulfilled values.

tryCatch

function tryCatch<A, E extends ResultError>(
fn: () => A,
onError: (error: unknown) => E,
): Result<A, E>;

Runs fn immediately and converts a thrown value to a tagged error.

tryCatchAsync

function tryCatchAsync<A, E extends ResultError>(
fn: () => Promise<A>,
onError: (error: unknown) => E,
): ResultAsync<A, E>;

Catches both a synchronous throw while creating the promise and a promise rejection.

Combinators

all

function all<T extends readonly Result<unknown, ResultError>[]>(
results: [...T],
): Result<
{
-readonly [K in keyof T]: T[K] extends Result<infer A, ResultError>
? A
: never;
},
{
[K in keyof T]: T[K] extends Result<
unknown,
infer E extends ResultError
>
? E
: never;
}[number]
>;

Walks the input tuple from left to right. It returns the first Err unchanged, or an Ok tuple preserving the value type at every position. The error type is the union of the input error types. Inputs have already been evaluated; all does not run them concurrently. The implementation uses private mapped-type aliases to express this return type; those aliases are not exported API.

firstOk

function firstOk<A, E extends ResultError>(
results: Result<A, E>[],
): Result<A, ResultAggregateError>;

Returns the first Ok. If every entry is an Err—including an empty array—it returns err(new ResultAggregateError(errors)).

ResultAggregateError

class ResultAggregateError extends Error {
readonly _tag: "ResultAggregateError";
readonly errors: ResultError[];
constructor(errors: ResultError[]);
}

The message joins the child messages as All results failed: …. The original error objects remain available in errors.

tap

function tap<A, E extends ResultError>(
result: Result<A, E>,
fn: (value: A) => void,
): Result<A, E>;

Calls fn only for Ok, then returns the same result object. Exceptions from fn propagate.

tapError

function tapError<A, E extends ResultError>(
result: Result<A, E>,
fn: (error: E) => void,
): Result<A, E>;

Calls fn only for Err, then returns the same result object. Exceptions from fn propagate.

Error inference and runtime checks

InferErrorTag<E>

type InferErrorTag<E extends ResultError> = E["_tag"];

Extracts a single error's tag type.

InferErrorTags<E>

type InferErrorTags<E extends ResultError> = E extends ResultError
? E["_tag"]
: never;

Distributes across an error union to produce the union of tag literals.

NarrowError<E, Tag>

type NarrowError<
E extends ResultError,
Tag extends string,
> = E extends { _tag: Tag } ? E : never;

Selects members of E whose _tag matches Tag.

isResultError

function isResultError(error: unknown): error is ResultError;

Returns true only when error instanceof Error and error._tag is a string. It does not require a literal tag at runtime.

assertResultError

function assertResultError(error: unknown): asserts error is ResultError;

Checks the same conditions as isResultError. It throws TypeError with a distinct message when the value is not an Error or lacks a string _tag.