Comparison
How @deessejs/fp compares to other error handling libraries
How does @deessejs/fp compare to other error handling libraries in the TypeScript ecosystem?
Quick Comparison
| Feature | @deessejs/fp | fp-ts | neverthrow | ts-results |
|---|---|---|---|---|
| Size (min+gzip) | ~5KB | ~40KB | ~6KB | ~8KB |
| Runtime deps | 0 | 1 (fp-ts) | 0 | 0 |
| Types | 5 | 20+ | 3 | 3 |
| Async support | Yes | Yes | No | No |
| Exhaustiveness checking | Yes | Yes | Partial | Yes |
@deessejs/fp vs fp-ts
fp-ts is a comprehensive functional programming library with many types and utilities.
fp-ts:
- 40KB bundle size (8x larger)
- Steep learning curve
- Rich ecosystem of abstractions
- Requires FP knowledge
@deessejs/fp:
- ~5KB (lightweight)
- Simple, pragmatic API
- Focused on error handling only
- No FP jargon
Use fp-ts if you need the full ecosystem of functional programming abstractions. Use @deessejs/fp if you just want type-safe error handling.
@deessejs/fp vs neverthrow
neverthrow is a Result type library for TypeScript.
neverthrow:
- Only Result type
- No async support
- Similar size (~6KB)
@deessejs/fp:
- 4 types (Result, Maybe, Try, AsyncResult)
- Built-in async handling
- Conversion utilities between types
- Slightly smaller
If you only need Result, neverthrow is a solid choice. @deessejs/fp gives you more types in a similar footprint.
@deessejs/fp vs ts-results
ts-results is another Result type implementation.
ts-results:
- Only Result type
- No Maybe or Try
- Larger bundle (~8KB)
@deessejs/fp:
- More types for different scenarios
- Smaller bundle
- Additional utilities (retry, sleep)
When to Choose @deessejs/fp
Choose @deessejs/fp when you want:
- Lightweight - ~5KB, zero runtime deps
- Comprehensive - 5 types for different error scenarios
- Pragmatic - No functional programming knowledge required
- TypeScript-first - Full type inference, no magic
- Async-ready - Built-in AsyncResult for network operations
Migration from other libraries
From try/catch
Ready to make the switch? Here's the simplest example:
// try/catch
try {
const data = JSON.parse(input);
} catch (e) {
console.error('Parse failed:', e.message);
}
// @deessejs/fp
import { attempt } from '@deessejs/fp';
const result = attempt(() => JSON.parse(input));
result.match({
onSuccess: (data) => console.log(data),
onError: (e) => console.error('Parse failed:', e.message)
});From neverthrow
// neverthrow
import { ok, err, Result } from "neverthrow";
const divide = (a: number, b: number): Result<number, string> => {
if (b === 0) return err("Division by zero");
return ok(a / b);
};
// @deessejs/fp - almost identical!
import { ok, err, Result } from "@deessejs/fp";
const divide = (a: number, b: number): Result<number, string> => {
if (b === 0) return err("Division by zero");
return ok(a / b);
};From fp-ts
// fp-ts
import { fromEither, tryCatch } from "fp-ts/TaskEither";
const parseJson = (json: string) =>
tryCatch(
() => JSON.parse(json),
() => new Error("Parse failed")
);
// @deessejs/fp - simpler!
import { attempt } from "@deessejs/fp";
const parseJson = (json: string) => attempt(() => JSON.parse(json));From throwing exceptions
// Before
function divide(a: number, b: number): number {
if (b === 0) throw new Error("Division by zero");
return a / b;
}
// After @deessejs/fp
import { ok, err, Result } from "@deessejs/fp";
const divide = (a: number, b: number): Result<number, string> => {
if (b === 0) return err("Division by zero");
return ok(a / b);
};