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 ​