Skip to main content

interoperability Zygos ↔ Neverthrow Interoperability

Real compatibility data. No guesswork. Analyzed against Neverthrow 8.2.0.

TL;DR

100% API compatible. Zygos Result is a drop-in replacement for Neverthrow with identical API and behavior.

MetricValue
Result API100% compatible
ResultAsync API100% compatible
Bundle Size2.6x smaller (~774 B vs ~1.96 kB)
Migration EffortImport change only
Bottom line

Change your import from neverthrow to pithos/zygos/result/result and you're done. Zero code changes required.


About Zygos Result

Zygos Result is a micro implementation of Neverthrow's Result type that is:

  • 2.6x smaller (~774 B vs ~1.96 kB) than Neverthrow 8.2.0
  • 100% API compatible - can be seamlessly replaced without code changes
  • Zero any types for better type safety
// Just swap your import
// Before
import { ok, err, Result, ResultAsync } from "neverthrow";

// After
import { ok, err, Result } from "pithos/zygos/result/result";
import { ResultAsync } from "pithos/zygos/result/result-async";

// Your existing code works as-is

checkmark Full API Compatibility

Click to expand each category and see the supported features:

Result Constructors (100%)2/2

ok(value), err(error)

import { ok, err, Result } from "pithos/zygos/result/result";

const success: Result<number, string> = ok(42);
const failure: Result<number, string> = err("Something went wrong");
Result Methods (100%)7/7

.isOk(), .isErr(), .map(), .mapErr(), .andThen(), .unwrapOr(), .match()

const result = ok(5)
.map(x => x * 2) // Transform success value
.mapErr(e => `Error: ${e}`) // Transform error value
.andThen(x => x > 0 ? ok(x) : err("negative")); // Chain operations

const value = result.unwrapOr(0); // Get value or default

const message = result.match(
value => `Success: ${value}`,
error => `Error: ${error}`
);
Result Static Methods (100%)2/2

Result.fromThrowable(), Result.combine()

// Wrap throwing functions
const safeParse = Result.fromThrowable(
JSON.parse,
(error) => `Parse error: ${error}`
);

const result = safeParse('{"valid": "json"}'); // Ok({valid: "json"})
const error = safeParse('invalid'); // Err("Parse error: ...")

// Combine multiple Results
const combined = Result.combine([ok(1), ok(2), ok(3)]); // Ok([1, 2, 3])
const withError = Result.combine([ok(1), err("fail"), ok(3)]); // Err("fail")
ResultAsync Constructors (100%)2/2

okAsync(), errAsync()

import { okAsync, errAsync, ResultAsync } from "pithos/zygos/result/result-async";

const asyncSuccess = okAsync(Promise.resolve(42));
const asyncError = errAsync("network error");
ResultAsync Methods (100%)7/7

.map(), .mapErr(), .andThen(), .unwrapOr(), .match(), .orElse(), .then()

const result = await okAsync(Promise.resolve(5))
.map(x => x * 2)
.andThen(x => okAsync(Promise.resolve(x.toString())));

// Pattern matching
const message = await result.match(
value => `Success: ${value}`,
error => `Error: ${error}`
);

// Fallback on error
const withFallback = await errAsync("error")
.orElse(() => okAsync("fallback"));
ResultAsync Static Methods (100%)4/4

ResultAsync.fromPromise(), ResultAsync.fromSafePromise(), ResultAsync.fromThrowable(), ResultAsync.combine()

// From potentially failing Promise
const result = ResultAsync.fromPromise(
fetch('/api/data'),
(error) => `Fetch failed: ${error}`
);

// From safe Promise (won't reject)
const safe = ResultAsync.fromSafePromise(Promise.resolve(42));

// Wrap async throwing functions
const safeFetch = ResultAsync.fromThrowable(
async (url: string) => {
const res = await fetch(url);
return res.json();
},
(error) => `Request failed: ${error}`
);

// Combine multiple async Results
const combined = ResultAsync.combine([
okAsync(1),
okAsync(2),
okAsync(3)
]); // Ok([1, 2, 3])
safeTry (100%)1/1
safeTry()
import { safeTry, ok, err } from "pithos/zygos/result/result";

// With generator function
const result = safeTry(function* () {
yield err("validation failed");
return ok(42);
});

// With direct function
const direct = safeTry(() => ok(42));

sparkles What Zygos adds

Beyond Neverthrow compatibility, Zygos brings unique features:

FeatureDescription
bundle size 2.6x smaller~774 B vs ~1.96 kB
padlock Zero any TypesBetter type safety with unknown types
convert fp-ts BridgesConvert to/from Option and Either
flash safeAsyncTrySimplified async error handling
target combineWithAllErrorsCollect all errors instead of stopping at first

fp-ts Interoperability

Zygos provides bridges to convert between Result and fp-ts types:

import { 
fromOption,
fromEither,
toEither,
ok,
err
} from "pithos/zygos/result/result";

// Option → Result
const someOption = { _tag: "Some", value: 42 };
const noneOption = { _tag: "None" };

const fromSome = fromOption(() => "No value")(someOption); // Ok(42)
const fromNone = fromOption(() => "No value")(noneOption); // Err("No value")

// Either → Result
const rightEither = { _tag: "Right", right: 42 };
const leftEither = { _tag: "Left", left: "error" };

const fromRight = fromEither(rightEither); // Ok(42)
const fromLeft = fromEither(leftEither); // Err("error")

// Result → Either
const okResult = ok(42);
const errResult = err("error");

const toRight = toEither(okResult); // { _tag: "Right", right: 42 }
const toLeft = toEither(errResult); // { _tag: "Left", left: "error" }

safeAsyncTry

Simplified async error handling without generators:

import { safeAsyncTry } from "pithos/zygos/result/result";

const fetchUser = async (id: string) => {
const response = await fetch(`/api/users/${id}`);
return response.json();
};

const result = await safeAsyncTry(() => fetchUser("123"));

if (result.isOk()) {
console.log(result.value); // User data
} else {
console.log(result.error); // Error details
}

combineWithAllErrors

Collect all errors instead of stopping at the first one:

import { ResultAsync, okAsync, errAsync } from "pithos/zygos/result/result-async";

const results = [
okAsync(1),
errAsync("error1"),
okAsync(3),
errAsync("error2")
];

const combined = ResultAsync.combineWithAllErrors(results);
const resolved = await combined;
// Err(["error1", "error2"]) - collects ALL errors

Ready to migrate? The complete step-by-step migration guide is in the Zygos module documentation: install, swap imports, and start using additional features. Go to migration guide →

Not sure which library fits your use case? See the comparison overview.


Why choose Zygos over Neverthrow?

AspectZygosNeverthrow
Bundle Size~774 B (2.6x smaller)~1.96 kB
Type SafetyZero any typesUses any in some places
fp-ts Bridgescheckmark fromOption, fromEither, toEithercross
safeAsyncTrycheckmark Simplified async handlingcross
combineWithAllErrorscheckmarkcheckmark
API Compatibility100% drop-in replacement-
Recommendation

If you're already using Neverthrow, switching to Zygos is straightforward: same API, smaller bundle, better types, and additional features. Just change your imports.


Related