Either<L, R>

Express success/failure with values

Elegant error handling that preserves error information without throwing exceptions

Either<L, R>

Express success/failure with values.

Overview

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.

Basic Usage

import { Either, Left, Right } from "functype/either"

// Creating Either values
const success = Right(42) // Right(42)
const failure = Left("error") // Left("error")

// Checking state
success.isRight() // true
failure.isLeft() // true

// Extracting values
success.orElse(0) // 42
failure.orElse(0) // 0
success.orThrow() // 42
failure.orThrow() // throws Error

Constructors

MethodDescription
Right(value)Create a Right (success) value
Left(error)Create a Left (error) value
Either.right(value)Same as Right()
Either.left(error)Same as Left()

Transformations

// Map - transform the Right value
Right(5).map((x) => x * 2) // Right(10)
Left("err").map((x) => x * 2) // Left("err") - unchanged

// MapLeft - transform the Left value
Left("err").mapLeft((e) => e.toUpperCase()) // Left("ERR")
Right(5).mapLeft((e) => e.toUpperCase()) // Right(5) - unchanged

// FlatMap - chain operations
Right(5).flatMap((x) => (x > 0 ? Right(x * 2) : Left("negative")))

// Bimap - transform both sides
either.bimap(
  (left) => `Error: ${left}`,
  (right) => right * 2,
)

Pattern Matching

// Using fold
const result = either.fold(
  (error) => `Failed: ${error}`,
  (value) => `Success: ${value}`,
)

// Using match pattern
const message = validateUser(input).fold(
  (errors) => `Validation failed: ${errors.join(", ")}`,
  (user) => `Welcome, ${user.name}!`,
)

Validation Pipeline

const validateAge = (age: number): Either<string, number> => (age >= 0 && age <= 120 ? Right(age) : Left("Invalid age"))

const validateName = (name: string): Either<string, string> => (name.length > 0 ? Right(name) : Left("Name required"))

// Chain validations
const validateUser = (data: UserInput) =>
  validateName(data.name).flatMap((name) => validateAge(data.age).map((age) => ({ name, age })))

Do-Notation

import { Do, $ } from "functype/do"

const result = Do(function* () {
  const name = yield* $(validateName(input.name))
  const age = yield* $(validateAge(input.age))
  const email = yield* $(validateEmail(input.email))
  return { name, age, email }
})

// Short-circuits on first Left

Key Features

  • Error Information: Preserve detailed error context instead of losing it with try-catch
  • Railway Oriented: Operations automatically short-circuit on Left
  • Composable Errors: Chain operations with mapLeft to transform errors
  • Type-Safe: Both success and error types are known at compile time

When to Use Either

  • Operations that can fail with detailed error info (validation, parsing, API calls)
  • Multiple validation steps in a pipeline
  • Railway-oriented programming (happy path and error path handled separately)
  • When you need typed errors at compile time

Type Conversions

either.toOption() // None for Left, Some(value) for Right
either.toTry() // Failure for Left, Success for Right
either.toPromise() // Rejected for Left, Resolved for Right

API Reference

See full API documentation at functype API docs