Announcing Resultify v2.1 — Now with ResultAsync

Functional error handling
reimagined for TypeScript

A lightweight, zero-dependency Result type inspired by Rust. Handle success and failure with total type safety, async pipelines, and zero runtime overhead.

example.ts
import { Result } from "@davemanufor/resultify";
function getUser(id: string): Result<User, "NOT_FOUND"> {
  const user = db.find(id);
  return Result.fromNullable(user, "NOT_FOUND");
}
const message = getUser("42").match({
  ok: (user) => `Hello, ${user.name}!`,
  err: () => "User not found",
});

Why Resultify?

The most complete Result implementation for the TypeScript ecosystem.

Type-Safe by Design

Force explicit handling of success and error cases. No more try/catch blocks leaking into your business logic.

Zero Runtime Bloat

Extremely lightweight with zero dependencies. Tree-shakeable and optimized for both browser and Node.js (18+).

Async Pipelines

Native ResultAsync support for chaining asynchronous operations without nested await statements.

Installation

Install via npm
npm install @davemanufor/resultify

Requires Node.js 18+ and TypeScript 4.5+. Works in all modern browsers.

Entry Points

ImportUse when
@davemanufor/resultifySync Result, Ok, Err, guards
@davemanufor/resultify/asyncResultAsync pipelines
@davemanufor/resultify/jestJest custom matchers (dev/test only)

Quick Start

The core of Resultify is the Result type. It represents either a success (Ok) or a failure (Err).

import { Result } from "@davemanufor/resultify";

// 1. Create results
const okResult = Result.ok(42);
const errResult = Result.err("Something went wrong");

// 2. Transform and chain
const doubled = okResult.map(n => n * 2);

// 3. Handle the outcome
doubled.match({
  ok: (val) => console.log(`Success: ${val}`),
  err: (err) => console.error(`Error: ${err}`),
});

Static Factories

Result.ok(value)

Creates a success (Ok) result containing the provided value. Fully infers the type of the value.

const res = Result.ok(42);
console.log(res.unwrap()); // 42

Result.err(error)

Creates a failure (Err) result containing the provided error. Errors can be strings, plain objects, or discriminated unions.

const res = Result.err("Not Found");
console.log(res.isErr()); // true

Result.try(fn)

Safely executes a synchronous function that might throw. Returns an Ok with the return value, or an Err wrapping the caught exception.

const res = Result.try(() => JSON.parse("invalid"));
// Result<any, unknown> (Err wrapping SyntaxError)

Result.fromNullable(value, error)

Converts a potentially null or undefined value into a Result. If the value is null/undefined, returns the provided error.

const user = db.getUser(); // User | null
const res = Result.fromNullable(user, "User not found");

Result.all(results)

Combines an array of Results. Short-circuits and returns the first Err it encounters, otherwise returns an Ok containing an array of values.

const combined = Result.all([
  Result.ok(1),
  Result.ok(2)
]); // Ok([1, 2])

Result.allSettled(results)

Collects the outcomes of all results without short-circuiting. Similar to Promise.allSettled.

const settled = Result.allSettled([
  Result.ok(1),
  Result.err("Error")
]); // [{ status: "ok", value: 1 }, { status: "err", reason: "Error" }]

Result.any(results)

Returns the first Ok result encountered. If all results are Errs, returns an Err containing an array of all the errors.

const any = Result.any([
  Result.err(1),
  Result.ok("success")
]); // Ok("success")

Result.partition(results)

Splits an array of mixed results into a tuple of [oks, errs], extracting their inner values.

const [oks, errs] = Result.partition([
  Result.ok(1),
  Result.err("e")
]); // oks: [1], errs: ["e"]

Result.fromAsync(fn)

Wraps an asynchronous function, returning a Promise that resolves to a Result. Catch mapped implicitly.

const res = await Result.fromAsync(async () => fetchData());
// Promise<Result<Data, unknown>>

Result.fromJSON(json)

Reconstructs a Result instance from the serialized output of toJSON().

const res = Result.fromJSON({ ok: true, value: 42 });
// Ok(42)

Instance Methods & Guards

ResultAsync

New in v2.0

Stop the "await-hell". Chain asynchronous operations as easily as synchronous ones. ResultAsync mirrors almost the entire synchronous Result API but returns Promises internally.

import { ResultAsync } from "@davemanufor/resultify/async";
// Automatically chain async promises without nested try/catch/await
const result = await ResultAsync.fromPromise(fetchUser(id))
  .flatMap(user => ResultAsync.fromPromise(getPosts(user.id)))
  .map(posts => posts.length)
  .match({
    ok: (count) => `User has ${count} posts`,
    err: (e) => `Failed: ${e.message}`,
  });

ResultAsync.all(results)

Concurrently awaits multiple ResultAsync operations, failing fast if any return an Err. Similar to Promise.all but for Results.

const batch = ResultAsync.all([
  ResultAsync.fromPromise(fetchUser("1")),
  ResultAsync.fromPromise(fetchUser("2")),
]);

.toResult()

Awaits the internal pipeline and returns a synchronous Result. You must call this (or match) to resolve the chain.

const asyncRes = ResultAsync.ok(42);
const syncRes = await asyncRes.toResult();
// Result.ok(42)

Type Safety

Resultify's greatest strength is its ability to handle any error type—not just Error objects. Use discriminated unions for rich, domain-specific error handling.

type AppError =
  | { type: "NOT_FOUND"; id: string }
  | { type: "VALIDATION"; fields: string[] };

function findUser(id: string): Result<User, AppError> {
  const user = db.get(id);
  return Result.fromNullable(user, { type: "NOT_FOUND", id });
}

Jest Matchers

Make your tests more readable with custom matchers. No more expect(res.isOk()).toBe(true).

  • toBeOk()
  • toBeErr()
  • toBeOkWith(value)
  • toBeErrWith(error)
// jest.setup.ts
import "@davemanufor/resultify/jest";

expect(result).toBeOkWith(42);

Advanced Patterns

const validation = Result.all([
  validateEmail(input.email),
  validatePassword(input.password),
  validateAge(input.age),
]);

// Inferred type: Result<[string, string, number], ValidationError>
if (validation.isOk()) {
  const [email, pass, age] = validation.unwrap();
}

Ready to handle errors better?

Start using Resultify in your TypeScript projects today.

© 2025 Resultify. MIT License.