Either<L, R>

Express success/failure with values

Elegant error handling that preserves error information without throwing exceptions

What is Either<L, R>?

Either represents a value that can be one of two types: Left (typically for errors) or Right (for success values). It's perfect for operations that can fail with meaningful error information.

// Success case
const success = Right<string, number>(42)
// Error case
const failure = Left<string, number>("Error occurred")

// Transform success values only
const doubled = success.map((n) => n * 2) // Right(84)
const _failed = failure.map((n) => n * 2) // Left("Error occurred")

// Handle both cases
const result = success.fold(
  (error) => `Failed: ${error}`,
  (value) => `Success: ${value}`,
) // "Success: 42"

// Chain operations that might fail
const divide = (a: number, b: number) => (b === 0 ? Left("Division by zero") : Right(a / b))

const calculation = Right(10)
  .flatMap((n) => divide(n, 2))
  .flatMap((n) => divide(n, 5)) // Right(1)

Key Features

Error Information

Preserve detailed error context instead of losing it with try-catch

Railway Oriented

Operations automatically short-circuit on Left, like a railway switch

Composable Errors

Chain operations with mapLeft to transform errors at each step

Type-Safe

Both success and error types are known at compile time

Common Patterns

Creating Either Values

// Success and failure
const success = Right<string, number>(42)
const failure = Left<string, number>("Error message")

// Transform success only
const doubled = success.map((n) => n * 2) // Right(84)
const unchanged = failure.map((n) => n * 2) // Left("Error message")

Validation Pipeline

const validateEmail = (email: string) => (email.includes("@") ? Right(email) : Left("Invalid email"))

const validateAge = (age: number) => (age >= 18 ? Right(age) : Left("Must be 18+"))

const result = Do(function* () {
  const email = yield* $(validateEmail("user@example.com"))
  const age = yield* $(validateAge(25))
  return { email, age }
})

Error Handling

const parseJSON = (json: string) => {
  try {
    return Right(JSON.parse(json))
  } catch (error) {
    return Left(`Parse error: ${error}`)
  }
}

const result = parseJSON('{"name": "Alice"}')
  .map((data) => data.name)
  .fold(
    (error) => `Error: ${error}`,
    (name) => `Hello, ${name}!`,
  )

When to Use Either

Operations that can fail with detailed error info

Validation, parsing, API calls with error responses

Multiple validation steps in a pipeline

Each step can fail independently with its own error

Railway-oriented programming

Happy path and error path handled separately