Skip to content

Getting started

This library brings Rust's Result and Option types to TypeScript with full type safety. This page first covers setup, then introduces both types through small examples.

Installation

bash
bun add results-ts
# or
npm install results-ts
# or
pnpm add results-ts
# or
deno add results-ts
# or
yarn add results-ts

Browser without a bundler

This library is an ES module. To use it directly in a browser, import it from a CDN inside a <script type="module">:

IMPORTANT

The type="module" attribute is required.

html
<script type="module">
    import { Ok } from 'https://unpkg.com/results-ts/dist/index.js';
    console.log(
        Ok(1)
            .map((x) => x + 1)
            .unwrap()
    ); // 2
</script>

Core concepts

Use Result when an operation can fail with a useful error. Use Option when a value may be absent and no error details are needed. Both types make each possible outcome explicit, without exceptions or repeated null checks.

Result

Result<T, E> represents either a success (Ok) carrying a value of type T, or a failure (Err) carrying an error of type E. Use it instead of throwing when failures are expected and recoverable.

typescript
import { Ok, Err } from 'results-ts';

const parseUserId = (id: string) => {
    const parsed = parseInt(id, 10);
    if (isNaN(parsed))
        return Err({
            code: 'INVALID_INPUT',
            message: 'ID must be a valid number'
        } as const);
    if (parsed <= 0)
        return Err({
            code: 'INVALID_ID',
            message: 'ID must be positive'
        } as const);
    return Ok(parsed);
};

const fetchUser = (id: number) => {
    if (id === 13)
        return Err({ code: 'NOT_FOUND', message: 'User not found' } as const);
    return Ok({ id, name: 'Alice', role: 'admin' });
};

const message = parseUserId('10')
    .map((id) => id + 3)
    .andThen(fetchUser)
    .match({
        Ok: (user) => `Welcome, ${user.role} ${user.name}!`,
        Err: (error) => {
            if (error.code === 'NOT_FOUND')
                return `Database Error: ${error.message}`;
            return `Validation Error: ${error.message}`;
        }
    });

NOTE

Methods like Result.unwrap(), Result.expect(), Result.unwrapErr(), and Result.expectErr() intentionally panic to mirror Rust. See the Error handling guide for the full story - and prefer Result.unwrapOr(), Result.unwrapOrElse(), or Result.match() when the failure case is recoverable.

Option

Option<T> represents either the presence of a value (Some) or its absence (None). Use it instead of null / undefined checks.

typescript
import { Some, None } from 'results-ts';

const parseNickname = (nickname?: string) => {
    if (!nickname) return None();
    const trimmed = nickname.trim();
    return trimmed.length > 0 ? Some(trimmed) : None();
};

const displayName = parseNickname('  Ada  ')
    .map((name) => name.toUpperCase())
    .match({
        Some: (name) => name,
        None: () => 'ANONYMOUS'
    });

Note that None is a function - always call it as None() (optionally typed, e.g. None<number>()). Convert an Option back to a Result with Option.okOr(err) or Option.okOrElse(() => err).

Next steps