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>
| Property | Type | Meaning |
|---|---|---|
_tag | "Ok" | outer discriminant |
value | A | success value |
Both properties are readonly.
Err<E>
| Property | Type | Meaning |
|---|---|---|
_tag | "Err" | outer discriminant |
error | E | tagged 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.