Skip to content

Factories: ok, err, tryCatch

Core constructors — barrel export.

Re-exports all factory/constructor functions for creating Result and Option values.

Creates a resolved async failure result.

export function asyncErr<E>(error: E): Promise<IResultOfT<never, E>>;

Defined in: factories/asyncErr.ts

import { asyncErr } from '@sandlada/result/factories';
import { map } from '@sandlada/result/promise-result';
const pending = asyncErr('nan');
const doubled = map((n: number) => n * 2, pending);
// doubled stays Err('nan'); the mapper never runs

Creates a resolved async success result.

export function asyncOk<T>(value: T): Promise<IResultOfT<T, never>>;

Defined in: factories/asyncOk.ts

import { asyncOk } from '@sandlada/result/factories';
import { map } from '@sandlada/result/promise-result';
const pending = asyncOk(21);
const doubled = map((n: number) => n * 2, pending);
// doubled resolves to Ok(42)

Creates a failure result carrying an error. The value type is never as a failure result has no meaningful value.

The dual-parameter overload (err<T, E>(error)) lets consumers widen the returned type without an explicit cast when the surrounding context already declares a wider value channel. See ok.ts for the symmetric rationale.

F# equivalent: Error e

export function err<E>(error: E): IResultOfT<never, E>;
export function err<T, E>(error: E): IResultOfT<T, E>;

Defined in: factories/err.ts

import { err, ok } from '@sandlada/result/factories';
import { map, match } from '@sandlada/result/operators';
import type { IResultOfT } from '@sandlada/result';
const rejected = err('nan');
const untouched = map((text: string) => Number(text) * 2, rejected);
const label = match(
(n) => `count=${n}`,
(error) => `failed:${error}`,
untouched,
);
// label === 'failed:nan'
const widen = <T>(): IResultOfT<T, string> => err('boom');
void ok(1);
void widen;

Tests a value against a predicate and wraps it in a Result. Returns Ok(value) if the predicate passes, Err(errorOnFalse) otherwise.

F# equivalent: custom Result.fromPredicate

export function fromPredicate<T, E>(
predicate: (v: T) => boolean,
errorOnFalse: E,
): (value: T) => IResultOfT<T, E>;
export function fromPredicate<T, E>(
predicate: (v: T) => boolean,
errorOnFalse: E,
value: T,
): IResultOfT<T, E>;

Defined in: factories/fromPredicate.ts

import { fromPredicate } from '@sandlada/result/factories';
import { map } from '@sandlada/result/operators';
const positive = fromPredicate((n: number) => n > 0, 'must be positive');
const doubled = map((n) => n * 2, positive(5));
const rejected = positive(0);
// doubled is Ok(10). rejected is Err('must be positive').

Wraps a Promise into an async result, catching rejections.

export async function fromPromise<T, E = unknown>(
promise: Promise<T>,
errorFn?: (error: unknown) => E,
): Promise<IResultOfT<T, E>>;

Defined in: factories/fromPromise.ts

import { fromPromise } from '@sandlada/result/factories';
import { map } from '@sandlada/result/promise-result';
const pending = Promise.resolve(21);
const doubled = map((n: number) => n * 2, fromPromise(pending));
const rejected = fromPromise(Promise.reject('offline'), (error) => `load failed: ${String(error)}`);
// doubled resolves to Ok(42). rejected resolves to Err('load failed: offline').

Wraps a Promise into a Result. On resolve returns ok(value); on reject returns err(error).

Mirrors fromPromise: takes an optional errorFn factory that maps a rejection onto the developer’s domain error shape. The error type defaults to Error and is widened when an errorFn is supplied that returns a different shape — e.g. fromSafePromise<T, MyError>(p, e => new MyError(e)).

export async function fromSafePromise<T, E = Error>(
promise: Promise<T>,
errorFn?: (error: unknown) => E,
): Promise<IResultOfT<T, E>>;

Defined in: factories/fromSafePromise.ts

import { fromSafePromise } from '@sandlada/result/factories';
import { unwrapOr } from '@sandlada/result/promise-result';
const ready = Promise.resolve(42);
const value = unwrapOr(0, fromSafePromise(ready));
const missing = fromSafePromise(Promise.reject('gone'));
// value resolves to 42. missing resolves to Err(Error('gone')).

Wraps a synchronous throwing function into a Result-returning function. Unlike tryCatch, fromThrowable returns a new function that returns Result — ideal for wrapping at definition time.

FP equivalent: lift a throwing function into the Result world.

export function fromThrowable<A extends unknown[], T, E = unknown>(
fn: (...args: A) => T,
errorFn?: (error: unknown) => E,
): (...args: A) => IResultOfT<T, E>;

Defined in: factories/fromThrowable.ts

import { fromThrowable } from '@sandlada/result/factories';
import { map } from '@sandlada/result/operators';
const parse = fromThrowable(
(raw: string) => JSON.parse(raw) as { a: number },
(error) => `invalid json: ${String(error)}`,
);
const field = map((body) => body.a, parse('{"a":1}'));
const broken = parse('nope');
// field is Ok(1). broken is Err('invalid json: ...').

Creates a success result carrying a value. The error type is never since a success result has no meaningful error.

The dual-parameter overload (ok<T, E>(value)) lets consumers widen the returned type without an explicit cast when the surrounding context already declares a wider error channel (e.g. inside an operator that returns IResultOfT<B, E2>). Without the overload, every consumer call site would need a cast to bridge IResultOfTSuccess<T> into the wider channel.

F# equivalent: Ok value

export function ok(): IResult<never>;
export function ok<T>(value: T): IResultOfT<T, never>;
export function ok<T, E>(value: T): IResultOfT<T, E>;

Defined in: factories/ok.ts

import { ok, err } from '@sandlada/result/factories';
import { map, match } from '@sandlada/result/operators';
import type { IResultOfT } from '@sandlada/result';
const parsed = ok('42');
const doubled = map((text: string) => Number(text) * 2, parsed);
const label = match(
(n) => `count=${n}`,
(error) => `failed:${String(error)}`,
doubled,
);
// label === 'count=84'
const failed = map((text: string) => Number(text) * 2, err('nan'));
// failed stays Err('nan'); map does not read the success value
const widen = <E>(): IResultOfT<number, E> => ok(42);
void widen;

Executes a synchronous function that may throw, and wraps the result. Unlike fromThrowable, tryCatch executes the function immediately.

export function tryCatch<T, E = unknown>(
fn: () => T,
errorFn?: (error: unknown) => E,
): IResultOfT<T, E>;

Defined in: factories/tryCatch.ts

import { tryCatch } from '@sandlada/result/factories';
import { unwrapOr } from '@sandlada/result/operators';
const parsed = tryCatch(() => JSON.parse('{"a":1}') as { a: number });
const field = unwrapOr({ a: 0 }, parsed);
const broken = tryCatch(
() => JSON.parse('nope'),
(error) => `invalid json: ${String(error)}`,
);
// field.a === 1. broken is Err('invalid json: ...').

Wraps an async function, catching rejections as failures.

export async function tryCatchAsync<T, E = unknown>(
fn: () => Promise<T>,
errorFn?: (error: unknown) => E,
): Promise<IResultOfT<T, E>>;

Defined in: factories/tryCatchAsync.ts

import { tryCatchAsync } from '@sandlada/result/factories';
import { map } from '@sandlada/result/promise-result';
const loaded = tryCatchAsync(
() => Promise.resolve('42'),
(error) => `load failed: ${String(error)}`,
);
const doubled = map((text: string) => Number(text) * 2, loaded);
// doubled resolves to Ok(84). A rejection becomes Err('load failed: ...').