Skip to content

zokugun/node-xtry

Repository files navigation

MIT licensed NPM Version Donation Donation Donation

Simple try/catch wrappers that always return a Result discriminated union, plus ready-made helpers (ok, err) for predictable control flow.

Why xtry?

  • Turn any sync or async function into an explicit Result object with zero dependencies.
  • Strong TypeScript types guide your control flow (fails and tagged errors).
  • Optional failure handlers let you log, meter, or mutate state exactly where the error occurs.

Installation

npm install @zokugun/xtry

Quick Start

import { xatry } from '@zokugun/xtry'

const userResult = await xatry(fetchUserFromApi());

if(userResult.fails) {
    console.error(userResult.error);
    return;
}

console.log('User loaded:', userResult.value);

Advanced Example

import { err, type Result, xatry, xtry } from '@zokugun/xtry'

export type FoobarError = { type: 'FOOBAR'; message: string };

async function foobar(): Result<number, FoobarError> {
    const result = await xatry(fetchUserFromApi());

    if(fails) {
        return err({ type: 'FOOBAR', message: 'The promise has failed...' });
    }

    return try(() => calculateAge(result.value));
}

async function main() {
    const result = await foobar();

    if(result.fails) {
        console.error(result.error.message);

        return;
    }

    console.log(result.value);
}

Partial Example

YResult extends the base Result union with a success flag so you can distinguish "valid failure" states from true errors.

import { err, ok, yerr, yok, type YResult } from '@zokugun/xtry'

function toNumber(input: string): YResult<number, MyError, 'empty-string'> {
    if(input.length > 0) {
        return yerr('empty-string');
    }

    const floatValue = Number.parseFloat(input);

    if(Number.isNaN(floatValue)) {
        return err({ type: '#VALUE!' });
    }

    return yok(floatValue);
}

function add(_x: string, _y: number): Result<number, MyError> {
    const x = toNumber(_x);
    if(x.fails) {
        return x;
    }
    if(!x.success) {
        return ok(0);
    }

    const y = toNumber(_y);
    if(y.fails) {
        return y;
    }
    if(!y.success) {
        return ok(0);
    }

    return x.value + y.value;
}

API reference

Result helpers

export type Success<T> = { fails: false; value: T; error: null };
export type Failure<E> = { fails: true; value: null; error: E };
export type Result<T, E> = Success<T> | Failure<E>;

export function ok<T>(value: T): Success<T>;
export function err<E>(error: E): Failure<E>;

Try helpers

export function xtry<T, E>(func: () => Exclude<T, Promise<unknown>>, handler?: (error: unknown) => void | E): Result<T, E>;
export function xatry<T, E>(func: (() => Exclude<T, Promise<unknown>>) | Promise<Exclude<T, Promise<unknown>>>, handler?: (error: unknown) => void | E): Promise<Result<T, E>>;

export function stringifyError(error: unknown): string;

Both helpers:

  • execute the supplied function and capture thrown values;
  • call the optional handler before turning that value into err(error);
  • never throw, making the return signature a reliable discriminated union.

Partial helpers

export type YSuccess<T> = Success<T> & { success: true };
export type YFailure<S> = { fails: false; success: false; type: S; value: null; error: null };
export type YResult<T, E, S> = Failure<E> | YSuccess<T> | YFailure<S>;

export function yok<T>(value: T): YSuccess<T>;
export function yerr<S>(type: S): YFailure<S>;

These helpers are useful when you need to separate soft rejections (success: false) from hard failures (fails: true).

Tips

  • Narrow on fails first, then use other flags (success, custom type or value) for the happy-path branching.

Donations

Support this project by becoming a financial contributor.

Ko-fi ko-fi.com/daiyam
Liberapay liberapay.com/daiyam/donate
PayPal paypal.me/daiyam99

License

Copyright © 2025-present Baptiste Augrain

Licensed under the MIT license.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published