Skip to content

What is Result?

Result.js implements Rust's Result<T, E> pattern for JavaScript/TypeScript, providing explicit, type-safe error handling without exceptions.

The Result Type

Result<T, E> represents an operation that can either succeed or fail:

typescript
type Result<T, E> = Ok<T, E> | Err<T, E>
  • Ok<T> — contains a success value
  • Err<E> — contains an error value

Result vs Exception-Based Error Handling

AspectExceptionResult
Error visibilityHidden in typesExplicit in signature
Compiler enforcementNoneEnforced by TypeScript
CompositionNested try-catchFluent chaining
RecoveryLimited patternsPattern matching
PerformanceStack unwindingZero overhead

Example: Before and After

With Exceptions

typescript
function divide(a: number, b: number): number {
  if (b === 0) throw new Error('Division by zero')
  return a / b
}

try {
  const result = divide(10, 0)
  console.log(result)
} catch (error) {
  console.error(error) // error type is unknown
}

With Result

typescript
function divide(a: number, b: number): Result<number, string> {
  if (b === 0) return Result.err('Division by zero')
  return Result.ok(a / b)
}

const result = divide(10, 0)

result.match({
  ok: (val) => console.log(val),
  err: (msg) => console.error(msg) // error type is explicit: string
})

Key Characteristics

Immutability

All operations return new Results — originals are never modified:

typescript
const original = Result.ok(5)
const doubled = original.map(x => x * 2)

console.log(original.unwrap()) // 5 (unchanged)
console.log(doubled.unwrap())  // 10

Explicit Error Handling

Results make failures visible in the type signature. While unwrap() is available, calling it on an Err throws at runtime — the pattern encourages handling both cases explicitly:

typescript
const result: Result<number, string> = divide(10, 0)

// ✗ Unsafe: throws at runtime if result is Err
const value = result.unwrap()

// ✓ Safe: check state first, TypeScript narrows the type
if (result.isOk()) {
  const value = result.unwrap() // Ok<number, string> — safe
}

// ✓ Preferred: pattern matching forces handling both cases
result.match({
  ok: (val) => console.log(val),
  err: (err) => console.error(err)
})

When to Use Result

Use Result for:

  • Expected errors (validation, not found, parsing failures)
  • Business logic failures (permission denied, insufficient funds)
  • Recoverable failures (network timeout, cache miss)
  • APIs where errors are common

Use exceptions for:

  • Unexpected errors (out of memory, programmer mistakes)
  • Fatal errors that cannot be recovered from

Core Methods Reference

MethodPurpose
Result.ok(value)Create success Result
Result.err(error)Create failure Result
result.isOk()Check if Ok
result.isErr()Check if Err
result.unwrap()Extract value (throws at runtime if Err)
result.unwrapOr(def)Extract with default
result.map(fn)Transform success value
result.andThen(fn)Chain operations
result.match({ok, err})Handle both cases

For the complete API, see API Reference.

Next Steps