npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@rustresult/result

v0.6.0

Published

Rust-like Result and ResultAsync for Javascript

Downloads

198

Readme

@rustresult/result

Rust-like Result and ResultAsync for JavaScript.

Result is a type that represents either success (Ok) or failure (Err), ResultAsync is the asynchronous version of Result.

Table Of Contents

Installation

> npm install @rustresult/result
> pnpm install @rustresult/result
> yarn add @rustresult/result

Usage

This package implements a Rust-like Result, nearly all methods are similar to the Rust Result.

const ok = Ok(1);
const err = Err('Some error message');
import fs, { Stats } from 'node:fs/promises';

const result1: Result<Stats, Error> = await fs
    .stat(path)
    .then((value) => Ok(value))
    .catch((err) => Err(err));

const readdir = resultifyAsync<Error>(fs.readdir);
const result2 = readdir(path, { withFileTypes: true });
//    ^ ResultAsync<Dirent[], Error>

Factories

Ok

Creates a Result that contains the success value.

Examples:

const result1 = Ok(1);
const result2 = Ok<number, string>(1);
const result3: Result<number, string> = Ok(1);

Err

Creates a Result that contains the error value.

Examples:

const result1 = Err('Some error message');
const result2 = Err<number, string>('Some error message');
const result3: Result<number, string> = Err('Some error message');

OkAsync

Creates a ResultAsync that contains the success value.

Examples:

const result1 = OkAsync(1);
const result2 = OkAsync<number, string>(1);
const result3: ResultAsync<number, string> = OkAsync(1);

ErrAsync

Creates a ResultAsync that contains the error value.

Examples:

const result1 = ErrAsync('Some error message');
const result2 = ErrAsync<number, string>('Some error message');
const result3: ResultAsync<number, string> = ErrAsync('Some error message');

fromPromiseableResult

Creates a ResultAsync from a promiseable Result.

Examples:

const result1 = fromPromiseableResult<number, string>(Ok(1));
const result2 = fromPromiseableResult<number, string>(Err('Some error message'));
const result3 = fromPromiseableResult<number, string>(Promise.resolve(Ok(1)));
const result4 = fromPromiseableResult<number, string>(Promise.resolve(Err('Some error message')));
const result5 = fromPromiseableResult<number, string>(OkAsync(1));
const result6 = fromPromiseableResult<number, string>(ErrAsync('Some error message'));

Methods

Rust Result Methods

The Rust-like Result and ResultAsync implements the following methods:

| Rust-like Result / ResultAsync method | Rust Result method | | :---------------------------------------- | :--------------------- | | isOk | is_ok | | isOkAnd | is_ok_and | | isErr | is_err | | isErrAnd | is_err_and | | ok | ok | | err | err | | map | map | | mapOr | map_or | | mapOrElse | map_or_else | | mapErr | map_err | | inspect | inspect | | inspectErr | inspect_err | | expect | expect | | unwrap | unwrap | | expectErr | expect_err | | unwrapErr | unwrap_err | | unwrapOr | unwrap_or | | unwrapOrElse | unwrap_or_else | | unwrapUnchecked | unwrap_unchecked | | unwrapErrUnchecked | unwrap_err_unchecked | | and | and | | andThen | and_then | | or | or | | orElse | or_else | | transpose | transpose |

Unlike Rust, JavaScript doesn't have the 'Ownership' feature, so some API like as_ref are not necessary. These implementations are not implemented:

<!-- implementations -->
as_ref
as_mut
inspect (unstable)
inspect_err (unstable)
as_deref
as_deref_mut
iter
iter_mut
unwrap_or_default
into_ok (unstable)
into_err (unstable)
copied
cloned
flatten (unstable)

<!-- some of trait implementations -->
clone
clone_from
fmt
hash

Synchronous Methods (Result)

Result.isOk

Returns true if the result is Ok.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

const x: Result<number, string> = Ok(2);
assert(x.isOk() === true);

const y: Result<number, string> = Err('Some error message');
assert(y.isOk() === false);
Result.isOkAnd

Returns true if the result is Ok and the value inside of it matches a predicate.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

const x: Result<number, string> = Ok(2);
assert(x.isOkAnd((value) => value > 1) === true);

const y: Result<number, string> = Ok(0);
assert(y.isOkAnd((value) => value > 1) === false);

const z: Result<number, string> = Err('Some error message');
assert(z.isOkAnd((value) => value > 1) === false);
Result.isErr

Returns true if the result is Err.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

const x: Result<number, string> = Ok(-3);
assert(x.isErr() === false);

const y: Result<number, string> = Err('Some error message');
assert(y.isErr() === true);
Result.isErrAnd

Returns true if the result is Err and the value inside of it matches a predicate.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

enum ErrorKind {
    NOT_FOUND,
    PERMISSION_DENIED,
}

const x: Result<number, ErrorKind> = Err(ErrorKind.NOT_FOUND);
assert(x.isErrAnd((value) => value === ErrorKind.NOT_FOUND) === true);

const y: Result<number, ErrorKind> = Err(ErrorKind.PERMISSION_DENIED);
assert(y.isErrAnd((value) => value === ErrorKind.NOT_FOUND) === false);

const z: Result<number, ErrorKind> = Ok(123);
assert(z.isErrAnd((value) => value === ErrorKind.NOT_FOUND) === false);
Result.ok

Converts from Result<T, E> to Optional<T> and discarding the error, if any.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

const x: Result<number, string> = Ok(2);
assert(x.ok() === 2);

const y: Result<number, string> = Err('Some error message');
assert(y.ok() === undefined);
Result.err

Converts from Result<T, E> to Optional<E> and discarding the success value, if any.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

const x: Result<number, string> = Ok(2);
assert(x.err() === undefined);

const y: Result<number, string> = Err('Some error message');
assert(y.err() === 'Some error message');
Result.map

Maps a Result<T, E> to Result<U, E> by applying a function to a contained Ok value, leaving an Err value untouched.

This function can be used to compose the results of two functions.

Examples:

import { Ok, type Result } from '@rustresult/result';

const x: Result<string, string> = Ok('foo');
assert(x.map((value) => value.length).ok() === 3);
Result.mapOr

Returns the provided fallback (if Err), or applies a function to the contained value (if Ok).

Arguments passed to mapOr are eagerly evaluated; if you are passing the result of a function call, it is recommended to use mapOrElse, which is lazily evaluated.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

const x: Result<string, string> = Ok('foo');
assert(x.mapOr(42, (value) => value.length) === 3);

const y: Result<string, string> = Err('bar');
assert(y.mapOr(42, (value) => value.length) === 42);
Result.mapOrElse

Maps a Result<T, E> to U by applying fallback function fallback to a contained Err value, or function map to a contained Ok value.

This function can be used to unpack a successful result while handling an error.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

const k = 21;

const x: Result<string, string> = Ok('foo');
assert(x.mapOrElse((err) => k * 2, (value) => value.length) === 3);

const y: Result<string, string> = Err('bar');
assert(y.mapOrElse((err) => k * 2, (value) => value.length) === 42);
Result.mapErr

Maps a Result<T, E> to Result<T, F> by applying a function to a contained Err value, leaving an Ok value untouched.

This function can be used to pass through a successful result while handling an error.

Examples:

import { Err, type Result } from '@rustresult/result';

const x: Result<number, Error> = Err(new Error('Some error message'));
assert(x.mapErr((err) => err.message).err() === 'Some error message');
Result.inspect

Calls the provided closure with a reference to the contained value if Ok.

Examples:

import { resultifySync } from '@rustresult/result';

const num = resultifySync<SyntaxError>()(JSON.parse)('4')
    .inspect((value: number) => console.log(`original: ${value}`))
    .map((value) => value ** 3)
    .expect('failed to parse number');
assert(num === 64);
Result.inspectErr

Calls the provided closure with a reference to the contained value if Err.

Examples:

import { resultifySync } from '@rustresult/result';

const num = resultifySync<SyntaxError>()(JSON.parse)('asdf')
    .inspectErr((err) => console.log(`failed to parse json string: ${err.message}`));
assert(num.err() instanceof SyntaxError);
Result.expect

Returns the contained Ok value.

Because this function may throw an error, its use is generally discouraged. Instead, prefer to call unwrapOr, unwrapOrElse.

Throws an Error if itself is Err, with an error message including the passed message, and the content of the Err.

Examples:

import { Err, type Result } from '@rustresult/result';

const x: Result<number, string> = Err('emergency failure');
x.expect('Failed to operate'); // throws Error('Failed to operate: emergency failure')
Result.unwrap

Returns the contained Ok value.

Because this function may throw an error, its use is generally discouraged. Instead, prefer to call unwrapOr, unwrapOrElse.

Throws an Error if itself is Err, with an error message provided by the Err's value.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

const x: Result<number, string> = Ok(2);
assert(x.unwrap() === 2);

const y: Result<number, string> = Err('emergency failure');
y.unwrap(); // throws Error('emergency failure')
Result.expectErr

Returns the contained Err value.

Throws an Error if itself is Err, with an error message provided by the Ok's value.

Examples:

import { Ok, type Result } from '@rustresult/result';

const x: Result<number, string> = Ok(10);
x.expectErr('Testing expectErr'); // throws Error('Testing expectErr: 10')
Result.unwrapErr

Returns the contained Err value.

Throws an Error if itself is Ok, with an error message provided by the Ok's value.

Examples:

import { Ok, type Result } from '@rustresult/result';

const x: Result<number, string> = Err('emergency failure');
assert(x.unwrapErr() === 'emergency failure');

const y: Result<number, string> = Ok(2);
y.unwrapErr(); // throws Error(2)
Result.unwrapOr

Returns the contained Ok value or a provided default.

Arguments passed to unwrapOr are eagerly evaluated; if you are passing the result of a function call, it is recommended to use unwrapOrElse, which is lazily evaluated.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

const $default = 2;
const x: Result<number, string> = Ok(9);
assert(x.unwrapOr($default) === 9);

const y: Result<number, string> = Err('error');
assert(y.unwrapOr($default) === $default);
Result.unwrapOrElse

Returns the contained Ok value or computes it from a closure.

Examples:

import { Err, Ok } from '@rustresult/result';

const count = (err: string) => err.length;
assert(Ok<number, string>(2).unwrapOrElse(count) === 2);
assert(Err<number, string>('foo').unwrapOrElse(count) === 3);
Result.unwrapUnchecked

Returns the contained Ok value, without checking that the value is not an Err.

SAFETY: Calling this method on an Err is undefined behavior. The safety contract must be upheld by the caller.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

const x: Result<number, string> = Ok(2);
assert(x.unwrapUnchecked() === 2);

const y: Result<number, string> = Err('emergency failure');
y.unwrapUnchecked();
Result.unwrapErrUnchecked

Returns the contained Err value, without checking that the value is not an Ok.

SAFETY: Calling this method on an Ok is undefined behavior. The safety contract must be upheld by the caller.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

const x: Result<number, string> = Ok(2);
x.unwrapErrUnchecked();

const y: Result<number, string> = Err('emergency failure');
assert(y.unwrapErrUnchecked() === 'emergency failure');
Result.and

Returns res if itself is Ok, otherwise returns the Err value of itself.

Arguments passed to and are eagerly evaluated; if you are passing the result of a function call, it is recommended to use andThen, which is lazily evaluated.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

let x: Result<number, string>;
let y: Result<string, string>;

x = Ok(2);
y = Err('late error');
assert(x.and(y).equal(Err('late error')));

x = Err('early error');
y = Ok('foo');
assert(x.and(y).equal(Err('early error')));

x = Err('not a 2');
y = Err('late error');
assert(x.and(y).equal(Err('not a 2')));

x = Ok(2);
y = Ok('different result type');
assert(x.and(y).equal(Ok('different result type')));
Result.andThen

Calls op if itself is Ok, otherwise returns the Err value of itself.

This function can be used for control flow based on Result values.

Examples:

import { Err, Ok, resultifySync } from '@rustresult/result';

const parseJSON = (json: string) =>
    resultifySync<SyntaxError>()(JSON.parse)(json).mapErr((err) => err.message);

assert(Ok<string, string>('2').andThen(parseJSON).equal(Ok(2)));
assert(
    Ok<string, string>('asdf')
        .andThen(parseJSON)
        .equal(Err('Unexpected token \'a\', "asdf" is not valid JSON')),
);
Result.or

Returns res if itself is Err, otherwise returns the Ok value of itself.

Arguments passed to or are eagerly evaluated; if you are passing the result of a function call, it is recommended to use orElse, which is lazily evaluated.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

let x: Result<number, string>;
let y: Result<number, string>;

x = Ok(2);
y = Err('late error');
assert(x.or(y).equal(Ok(2)));

x = Err('early error');
y = Ok(2);
assert(x.or(y).equal(Ok(2)));

x = Err('not a 2');
y = Err('late error');
assert(x.or(y).equal(Err('late error')));

x = Ok(2);
y = Ok(100);
assert(x.or(y).equal(Ok(2)));
Result.orElse

Calls op if the result is Err, otherwise returns the Ok value of self.

This function can be used for control flow based on Result values.

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

const sq = (num: number): Result<number, number> => Ok(num * num);
const err = (num: number): Result<number, number> => Err(num);

assert(Ok(2).orElse(sq).orElse(sq).equal(Ok(2)));
assert(Ok(2).orElse(err).orElse(sq).equal(Ok(2)));
assert(Err<number, number>(3).orElse(sq).orElse(err).equal(Ok(9)));
assert(Err<number, number>(3).orElse(err).orElse(err).equal(Err(3)));
Result.transpose

Transposes a Result of an optional value into an optional of a Result.

Ok(undefined | null) will be mapped to undefined. Ok(_) and Err(_) will be mapped to Ok(_) and Err(_).

Examples:

import { Err, Ok, type Result } from '@rustresult/result';

type SomeErr = unknown;

let x: Result<number | undefined | null, SomeErr>;
let y: Result<number, SomeErr> | undefined;

x = Ok(5);
y = Ok(5);
assert(x.transpose()!.equal(y));

x = Ok(undefined);
y = undefined;
assert(x.transpose() === y);

x = Ok(null);
y = undefined;
assert(x.transpose() === y);

Asynchronous Methods (ResultAsync)

ResultAsync.isOk

Asynchornously returns true if the result is Ok.

Examples:

import { ErrAsync, OkAsync, type ResultAsync } from '@rustresult/result';

const x: ResultAsync<number, string> = OkAsync(2);
assert((await x.isOk()) === true);

const y: ResultAsync<number, string> = ErrAsync('Some error message');
assert((await y.isOk()) === false);
ResultAsync.isOkAnd

Asynchronously returns true if the result is Ok and the value inside of it matches a predicate.

Examples:

import { ErrAsync, OkAsync, type ResultAsync } from '@rustresult/result';

const x: ResultAsync<number, string> = OkAsync(2);
assert((await x.isOkAnd((value) => Promise.resolve(value > 1))) === true);

const y: ResultAsync<number, string> = OkAsync(0);
assert((await y.isOkAnd((value) => Promise.resolve(value > 1))) === false);

const z: ResultAsync<number, string> = ErrAsync('Some error message');
assert((await z.isOkAnd((value) => Promise.resolve(value > 1))) === false);
ResultAsync.isErr

Asynchornously returns true if the result is Err.

Examples:

import { ErrAsync, OkAsync, type ResultAsync } from '@rustresult/result';

const x: ResultAsync<number, string> = OkAsync(-3);
assert((await x.isErr()) === false);

const y: ResultAsync<number, string> = ErrAsync('Some error message');
assert((await y.isErr()) === true);
ResultAsync.isErrAnd

Asynchronously returns true if the result is Err and the value inside of it matches a predicate.

Examples:

import { ErrAsync, OkAsync, type ResultAsync } from '@rustresult/result';

enum ErrorKind {
    NOT_FOUND,
    PERMISSION_DENIED,
}

const x: ResultAsync<number, ErrorKind> = ErrAsync(ErrorKind.NOT_FOUND);
assert((await x.isErrAnd((value) => Promise.resolve(value === ErrorKind.NOT_FOUND))) === true);

const y: ResultAsync<number, ErrorKind> = ErrAsync(ErrorKind.PERMISSION_DENIED);
assert((await y.isErrAnd((value) => Promise.resolve(value === ErrorKind.NOT_FOUND))) === false);

const z: ResultAsync<number, ErrorKind> = OkAsync(123);
assert((await z.isErrAnd((value) => Promise.resolve(value === ErrorKind.NOT_FOUND))) === false);
ResultAsync.ok

Asynchornously converts from ResultAsync<T, E> to Optional<T> and discarding the error, if any.

Examples:

import { ErrAsync, OkAsync, type ResultAsync } from '@rustresult/result';

const x: ResultAsync<number, string> = OkAsync(2);
assert((await x.ok()) === 2);

const y: ResultAsync<number, string> = ErrAsync('Some error message');
assert((await y.ok()) === undefined);
ResultAsync.err

Asynchornously converts from ResultAsync<T, E> to Optional<E> and discarding the success value, if any.

Examples:

import { ErrAsync, OkAsync, type ResultAsync } from '@rustresult/result';

const x: ResultAsync<number, string> = OkAsync(2);
assert((await x.err()) === undefined);

const y: ResultAsync<number, string> = ErrAsync('Some error message');
assert((await y.err()) === 'Some error message');
ResultAsync.map

Asynchronously maps a ResultAsync<T, E> to ResultAsync<U, E> by applying a function to a contained Ok value, leaving an Err value untouched.

This function can be used to compose the results of two functions.

Examples:

import { OkAsync } from '@rustresult/result';

const x = OkAsync<string, string>('foo').map((value) => Promise.resolve(value.length));
assert((await x.ok()) === 3);
ResultAsync.mapOr

Asynchronously returns the provided fallback (if Err), or applies a function to the contained value (if Ok).

Arguments passed to mapOr are eagerly evaluated; if you are passing the result of a function call, it is recommended to use mapOrElse, which is lazily evaluated.

Examples:

import { ErrAsync, OkAsync, type ResultAsync } from '@rustresult/result';

const x: ResultAsync<string, string> = OkAsync('foo');
assert((await x.mapOr(42, (value) => value.length)) === 3);

const y: ResultAsync<string, string> = ErrAsync('bar');
assert((await y.mapOr(42, (value) => value.length)) === 42);
ResultAsync.mapOrElse

Asynchronously maps a ResultAsync<T, E> to U by applying fallback function fallback to a contained Err value, or function map to a contained Ok value.

This function can be used to unpack a successful result while handling an error.

Examples:

import { ErrAsync, OkAsync, type ResultAsync } from '@rustresult/result';

const k = 21;

const x: ResultAsync<string, string> = OkAsync('foo');
assert((await x.mapOrElse(() => Promise.resolve(k * 2), (value) => Promise.resolve(value.length))) === 3);

const y: ResultAsync<string, string> = ErrAsync('bar');
assert((await y.mapOrElse(() => Promise.resolve(k * 2), (value) => Promise.resolve(value.length))) === 42);
ResultAsync.mapErr

Asynchronously maps a ResultAsync<T, E> to ResultAsync<T, F> by applying a function to a contained Err value, leaving an Ok value untouched.

This function can be used to pass through a successful result while handling an error.

Examples:

import { ErrAsync } from '@rustresult/result';

const x = ErrAsync(new Error('Some error message')).mapErr((err) => Promise.resolve(err.message));
assert((await x.err()) === 'Some error message');
ResultAsync.inspect

Asynchronously calls the provided closure with a reference to the contained value if Ok.

Examples:

const num = await OkAsync(4)
    .inspect((value) => {
        console.log(`original: ${value}`);
    })
    .map((value) => value ** 3)
    .expect('Some error message');
assert(num === 64);
ResultAsync.inspectErr

Asynchronously calls the provided closure with a reference to the contained value if Err.

Examples:

const result = ErrAsync(new SyntaxError('Some error message')).inspectErr((err) => {
    console.log(`failed to do something: ${err.message}`);
});
assert((await result.err()) instanceof SyntaxError);
ResultAsync.expect

Asynchronously returns the contained Ok value.

Because this function may throw an error, its use is generally discouraged. Instead, prefer to call unwrapOr, unwrapOrElse.

Throws an Error if itself is Err, with an error message including the passed message, and the content of the Err.

Examples:

import { ErrAsync, type ResultAsync } from '@rustresult/result';

const x: ResultAsync<number, string> = ErrAsync('emergency failure');
await x.expect('Failed to operate'); // throws Error('Failed to operate: emergency failure')
ResultAsync.unwrap

Asynchronously returns the contained Ok value.

Because this function may throw an error, its use is generally discouraged. Instead, prefer to call unwrapOr, unwrapOrElse.

Throws an Error if itself is Err, with an error message provided by the Err's value.

Examples:

import { ErrAsync, OkAsync, type ResultAsync } from '@rustresult/result';

const x: ResultAsync<number, string> = OkAsync(2);
assert((await x.unwrap()) === 2);

const y: ResultAsync<number, string> = ErrAsync('emergency failure');
await y.unwrap(); // throws Error('emergency failure')
ResultAsync.expectErr

Asynchronously returns the contained Err value.

Throws an Error if itself is Err, with an error message provided by the Ok's value.

Examples:

import { OkAsync, type ResultAsync } from '@rustresult/result';

const x: ResultAsync<number, string> = OkAsync(10);
await x.expectErr('Testing expectErr'); // throws Error('Testing expectErr: 10')
ResultAsync.unwrapErr

Asynchronously returns the contained Err value.

Throws an Error if itself is Ok, with an error message provided by the Ok's value.

Examples:

import { OkAsync, type ResultAsync } from '@rustresult/result';

const x: ResultAsync<number, string> = Err('emergency failure');
assert((await x.unwrapErr()) === 'emergency failure');

const y: ResultAsync<number, string> = OkAsync(2);
await y.unwrapErr(); // throws Error(2)
ResultAsync.unwrapOr

Asynchronously returns the contained Ok value or a provided default.

Arguments passed to unwrapOr are eagerly evaluated; if you are passing the result of a function call, it is recommended to use unwrapOrElse, which is lazily evaluated.

Examples:

import { ErrAsync, OkAsync, type ResultAsync } from '@rustresult/result';

const $default = 2;
const x: ResultAsync<number, string> = OkAsync(9);
assert((await x.unwrapOr($default)) === 9);

const y: ResultAsync<number, string> = ErrAsync('error');
assert((await y.unwrapOr($default)) === $default);
ResultAsync.unwrapOrElse

Asynchronously returns the contained Ok value or computes it from a closure.

Examples:

import { ErrAsync, OkAsync } from '@rustresult/result';

const count = (err: string) => Promise.resolve(err.length);
assert((await OkAsync<number, string>(2).unwrapOrElse(count)) === 2);
assert((await ErrAsync<number, string>('foo').unwrapOrElse(count)) === 3);
ResultAsync.unwrapUnchecked

Asynchronously returns the contained Ok value, without checking that the value is not an Err.

SAFETY: Calling this method on an Err is undefined behavior. The safety contract must be upheld by the caller.

Examples:

import { ErrAsync, OkAsync, type ResultAsync } from '@rustresult/result';

const x: ResultAsync<number, string> = OkAsync(2);
assert((await x.unwrapUnchecked()) === 2);

const y: ResultAsync<number, string> = ErrAsync('emergency failure');
await y.unwrapUnchecked();
ResultAsync.unwrapErrUnchecked

Asynchronously returns the contained Err value, without checking that the value is not an Ok.

SAFETY: Calling this method on an Ok is undefined behavior. The safety contract must be upheld by the caller.

Examples:

import { ErrAsync, OkAsync, type ResultAsync } from '@rustresult/result';

const x: ResultAsync<number, string> = OkAsync(2);
await x.unwrapErrUnchecked();

const y: ResultAsync<number, string> = ErrAsync('emergency failure');
assert((await y.unwrapErrUnchecked()) === 'emergency failure');
ResultAsync.and

Asynchronously returns res if itself is Ok, otherwise returns the Err value of itself.

Arguments passed to and are eagerly evaluated; if you are passing the result of a function call, it is recommended to use andThen, which is lazily evaluated.

Examples:

import { Err, ErrAsync, Ok, OkAsync, type ResultAsync } from '@rustresult/result';

let x: ResultAsync<number, string>;
let y: ResultAsync<string, string>;

x = OkAsync(2);
y = ErrAsync('late error');
assert(await x.and(y).equal(Err('late error')));

x = ErrAsync('early error');
y = OkAsync('foo');
assert(await x.and(y).equal(Err('early error')));

x = ErrAsync('not a 2');
y = ErrAsync('late error');
assert(await x.and(y).equal(Err('not a 2')));

x = OkAsync(2);
y = OkAsync('different result type');
assert(await x.and(y).equal(Ok('different result type')));
ResultAsync.andThen

Asynchronously calls op if itself is Ok, otherwise returns the Err value of itself.

This function can be used for control flow based on ResultAsync values.

Examples:

import { Err, ErrAsync, Ok, OkAsync, type ResultAsync } from '@rustresult/result';

const sq = (num: number): ResultAsync<number, number> => OkAsync(num * num);
const err = (num: number): ResultAsync<number, number> => ErrAsync(num);

const x = OkAsync<number, number>(2).andThen(sq).andThen(sq);
assert(await x.equal(Ok(16)));

const y = OkAsync<number, number>(2).andThen(sq).andThen(err);
assert(await y.equal(Err(4)));

const z = OkAsync<number, number>(2).andThen(err).andThen(err);
assert(await z.equal(Err(2)));
ResultAsync.or

Returns res if itself is Err, otherwise returns the Ok value of itself.

Arguments passed to or are eagerly evaluated; if you are passing the result of a function call, it is recommended to use orElse, which is lazily evaluated.

Examples:

import { Err, ErrAsync, Ok, OkAsync, type ResultAsync } from '@rustresult/result';

let x: ResultAsync<number, string>;
let y: ResultAsync<number, string>;

x = OkAsync(2);
y = ErrAsync('late error');
assert(await x.or(y).equal(Ok(2)));

x = ErrAsync('early error');
y = OkAsync(2);
assert(await x.or(y).equal(Ok(2)));

x = ErrAsync('not a 2');
y = ErrAsync('late error');
assert(await x.or(y).equal(Err('late error')));

x = OkAsync(2);
y = OkAsync(100);
assert(await x.or(y).equal(Ok(2)));
ResultAsync.orElse

Asynchronously calls op if the result is Err, otherwise returns the Ok value of self.

This function can be used for control flow based on ResultAsync values.

Examples:

import { Err, ErrAsync, Ok, OkAsync, type ResultAsync } from '@rustresult/result';

const sq = (num: number): ResultAsync<number, number> => OkAsync(num * num);
const err = (num: number): ResultAsync<number, number> => ErrAsync(num);

const x = OkAsync(2).orElse(sq).orElse(sq);
assert(await x.equal(Ok(2)));

const y = ErrAsync<number, number>(3).orElse(sq).orElse(err);
assert(await y.equal(Ok(9)));

const z = ErrAsync<number, number>(3).orElse(err).orElse(err);
assert(await z.equal(Err(3)));
ResultAsync.transpose

Asynchronously transposes a ResultAsync of an optional value into an optional of a ResultAsync.

OkAsync(undefined | null) will be mapped to Promise<undefined>. OkAsync(_) and ErrAsync(_) will be mapped to OkAsync(_) and ErrAsync(_).

Examples:

import { OkAsync, type ResultAsync } from '@rustresult/result';

type SomeErr = unknown;

let x: ResultAsync<number | undefined | null, SomeErr>;
let y: ResultAsync<number, SomeErr> | undefined;

x = OkAsync(5);
y = OkAsync(5);
assert(await x.transpose()!.equal(y));

x = OkAsync(undefined);
y = undefined;
assert((await x.transpose()) === y);

x = OkAsync(null);
y = undefined;
assert((await x.transpose()) === y);

Additional Methods

.equal

You can not just use === or == to compare Result or ResultAsync, so Result and ResultAsync themselves provide an method call equal for that.

There is no built-in deep-equal support in this package for array, object, built-in classes like Date, custom classes. If you do want to deeply compare those complex structures, you will have to write your own helper functions.

There is a proposal (stage 2) that introduces Record and Tuple which are compared by content rather than identity. In the future, we can use Record and Tuple in Result so that we don't need to implement custom equality comparison function.

Result.equal

Returns true if self equals to other.

Examples:

import { Err, Ok } from '@rustresult/result';

assert(Ok(1).equal(Ok(1)));
assert(Ok(NaN).equal(Ok(NaN)));
assert(Err('err').equal(Err('err')));

assert(Ok(1).equal(Ok(2)) === false);
assert(Err('err 1').equal(Err(-1)) === false);

assert(Ok(Ok(1)).equal(Ok(Ok(1))));
assert(Ok(Err('err')).equal(Ok(Err('err'))));
assert(Err(Err('err')).equal(Err(Err('err'))));
assert(Err(Ok(1)).equal(Err(Ok(1))));

assert(Ok(Ok(1)).equal(Ok(Ok(2))) === false);
assert(Ok(Ok(1)).equal(Ok(Err('err'))) === false);
assert(Err(Ok(1)).equal(Err(Err('err'))) === false);

assert(Ok([1]).equal(Ok([1])) === false);
assert(Ok({ foo: 1 }).equal(Ok({ foo: 1 })) === false);
assert(Ok(Ok([1])).equal(Ok(Ok([1]))) === false);
assert(Ok(Ok({ foo: 1 })).equal(Ok(Ok({ foo: 1 }))) === false);
ResultAsync.equal

Asynchronously returns true if self equals to other.

Examples:

import { Err, ErrAsync, Ok, OkAsync, type ResultAsync } from '@rustresult/result';

assert(await OkAsync(1).equal(Ok(1)));
assert(await OkAsync(1).equal(Promise.resolve(Ok(1))));
assert(await OkAsync(1).equal(OkAsync(1)));

assert((await OkAsync(1).equal(Ok(2))) === false);
assert((await OkAsync(1).equal(Promise.resolve(Ok(2)))) === false);
assert((await OkAsync(1).equal(OkAsync(2))) === false);

assert(await OkAsync(Ok(1)).equal(Ok(Ok(1))));
assert(await OkAsync(Ok(1)).equal(Ok(OkAsync(1))));
assert(await OkAsync(Ok(1)).equal(Promise.resolve(Ok(Ok(1)))));
assert(await OkAsync(Ok(1)).equal(OkAsync(Promise.resolve(Ok(1)))));
assert(await OkAsync(Ok(1)).equal(OkAsync(OkAsync(1))));
assert(await OkAsync(Promise.resolve(Ok(1))).equal(Promise.resolve(Ok(OkAsync(1)))));
assert(await OkAsync(OkAsync(1)).equal(OkAsync(Ok(1))));

assert((await OkAsync([1]).equal(Ok([1]))) === false);
assert((await OkAsync({ foo: 1 }).equal(Promise.resolve(Ok({ foo: 1 })))) === false);
assert((await ErrAsync({ message: 'err' }).equal(ErrAsync({ message: 'err' }))) === false);

assert((await OkAsync(Ok([1])).equal(Ok(Ok([1])))) === false);
assert((await OkAsync(Ok([1])).equal(OkAsync(OkAsync([1])))) === false);
assert((await OkAsync(Promise.resolve(Ok([1]))).equal(OkAsync(Ok([1])))) === false);
assert((await OkAsync(Promise.resolve(Ok({ foo: 1 }))).equal(Ok(OkAsync({ foo: 1 })))) === false);
assert((await OkAsync(OkAsync({ foo: 1 })).equal(OkAsync(OkAsync({ foo: 1 })))) === false);

Result.async

Converts this result to an async Result so it can work in asynchronous code.

Examples:

import { Ok } from '@rustresult/result';

function fn(value: number): Promise<number> {
    // do something asynchronously
    return Promise.resolve(value ** 2);
}

const num = await Ok<number, string>(3)
    .async()
    .map(fn)
    .inspectErr((err) => {
        console.log(err);
    })
    .ok();
assert(num === 9);

Helpers for Resultifying

resultifyAsync

Takes a function and returns a version that returns results asynchronously.

import fs from 'node:fs/promises';
import { resultifyAsync } from '@rustresult/result';

const copyFile1 = resultifyAsync(fs.copyFile);
const copyFile2 = resultifyAsync<Error>()(fs.copyFile);

resultifySync

Takes a function and returns a version that returns results synchronously.

import { resultifySync } from '@rustresult/result';

/**
 * @throws {Error} Some error messages
 */
function fn(): string {
    // do something
}

const fn1 = resultifySync(fn);
const fn1 = resultifySync<Error>()(fn);

In the context where async functions are not allowed, you can use this function to resultify the sync function.

resultifyPromise

Takes a promise and returns a new promise that contains a result.

import { resultifyPromise } from '@rustresult/result';

const result = await resultifyPromise(promise);

Due to the limit of TypeScript,it's impossible to resultify overloaded functions perfectly that the returned functions are still overloaded. This function allows you to resultify the promise that the overloaded functions return.

Write Your Own Implementation of Result?

Although you do have the ability to do so, it's not recommended that you write your own implementation.

The default implementation that this package provides should meet your requirements in most cases. If if leaks some abilities please feel free to file an issue.