A lightweight and functional-style library that provides robust abstractions for handling optional values and handling operations that can either succeed or fail. By making states explicit, it encourages precise and deliberate management of application logic.
eaux introduces two core abstractions:
- 
MaybeRepresents an optional value. A
Maybecan either be aNothingcontaining no value or aSomethingcontaining a value. - 
ResultRepresents the outcome of an operation that can either succeed or fail. A
Resultcan either be aFailurecontaining an error or aSuccesscontaining a value. 
Both abstractions support a suite of chainable and composable operations that lead to code that is clear, consistent, and reliable.
To install eaux, ensure that you have Node.js version 20 or newer, and use your preferred package manager.
npm install eauxpnpm add eauxyarn add eauxBelow is a complete overview of the functions and methods exposed by the library.
- 
something<TValue = any>(value: TValue): Maybe<TValue>Creates and returns a new
SomethingMaybecontaining the providedvalue. - 
nothing<TValue = any>(): Maybe<TValue>Creates and returns a new
NothingMaybe. - 
isMaybe(value: unknown): value is Maybe<unknown>Checks if the provided
valueis aMaybe. 
On a Maybe instance, the following methods are available:
- 
and<TOtherValue>(other: Maybe<TOtherValue>): Maybe<TOtherValue>If this is a
SomethingMaybe, returnsother. If this is aNothingMaybe, returns thisMaybe. - 
andThen<TOtherValue>(f: (value: TValue) => Maybe<TOtherValue>): Maybe<TOtherValue>If this is a
SomethingMaybe, returns the result of applyingfto the contained value. If this is aNothingMaybe, returns thisMaybe. - 
expect(message: string): TValueIf this is a
SomethingMaybe, returns the contained value. If this is aNothingMaybe, throws anExpectationErrorwith the providedmessage. - 
filter(predicate: (value: TValue) => boolean): Maybe<TValue>If this is a
SomethingMaybe, returns thisMaybeif the contained value satisfies the providedpredicate. If this is aNothingMaybe, returns thisMaybe. - 
getSuccessOr<TError>(error: TError): Result<TValue, TError>If this is a
SomethingMaybe, returns aSuccessResultcontaining the contained value. If this is aNothingMaybe, returns aFailureResultcontaining the providederror. - 
inspect(f: (value: TValue) => void): Maybe<TValue>If this is a
SomethingMaybe, appliesfto the contained value and returns thisMaybe. If this is aNothingMaybe, returns thisMaybe. - 
isNothing(): booleanIf this is a
SomethingMaybe, returnsfalse. If this is aNothingMaybe, returnstrue. - 
isNothingOr(predicate: (value: TValue) => boolean): booleanIf this is a
SomethingMaybe, returns the result of applyingpredicateto the contained value. If this is aNothingMaybe, returnstrue. - 
isSomething(): booleanIf this is a
SomethingMaybe, returnstrue. If this is aNothingMaybe, returnsfalse. - 
isSomethingAnd(predicate: (value: TValue) => boolean): booleanIf this is a
SomethingMaybe, returns the result of applyingpredicateto the contained value. If this is aNothingMaybe, returnsfalse. - 
map<TNewValue>(f: (value: TValue) => TNewValue): Maybe<TNewValue>If this is a
SomethingMaybe, returns aSomethingMaybecontaining the result of applyingfto the contained value. If this is aNothingMaybe, returns thisMaybe. - 
or(other: Maybe<TValue>): Maybe<TValue>If this is a
SomethingMaybe, returns thisMaybe. If this is aNothingMaybe, returnsother. - 
unwrap(): TValueIf this is a
SomethingMaybe, returns the contained value. If this is aNothingMaybe, throws anImproperUnwrapError. 
- 
success<TValue = any, TError = any>(value: TValue): Result<TValue, TError>Creates and returns a new
SuccessResultcontaining the providedvalue. - 
failure<TValue = any, TError = any>(error: TError): Result<TValue, TError>Creates and returns a new
FailureResultcontaining the providederror. - 
isResult(value: unknown): value is Result<unknown, unknown>Checks if the provided
valueis aResult. 
On a Result instance, the following methods are available:
- 
and<TOtherValue>(other: Result<TOtherValue, TError>): Result<TOtherValue, TError>If this is a
SuccessResult, returnsother. If this is aFailureResult, returns thisResult. - 
andThen<TOtherValue>(f: (value: TValue) => Result<TOtherValue, TError>): Result<TOtherValue, TError>If this is a
SuccessResult, returns the result of applyingfto the contained value. If this is aFailureResult, returns thisResult. - 
expect(message: string): TValueIf this is a
SuccessResult, returns the contained value. If this is aFailureResult, throws anExpectationErrorwith the providedmessage. - 
expectFailure(message: string): TErrorIf this is a
SuccessResult, throws anExpectationErrorwith the providedmessage. If this is aFailureResult, returns the contained error. - 
getFailure(): Maybe<TError>If this is a
SuccessResult, returns aNothingMaybe. If this is aFailureResult, returns aSomethingMaybecontaining the contained error. - 
getSuccess(): Maybe<TValue>If this is a
SuccessResult, returns aSomethingMaybecontaining the contained value. If this is aFailureResult, returns aNothingMaybe. - 
inspect(f: (value: TValue) => void): Result<TValue, TError>If this is a
SuccessResult, appliesfto the contained value and returns thisResult. If this is aFailureResult, returns thisResult. - 
inspectFailure(f: (error: TError) => void): Result<TValue, TError>If this is a
SuccessResult, returns thisResult. If this is aFailureResult, appliesfto the contained error and returns thisResult. - 
isFailure(): booleanIf this is a
SuccessResult, returnsfalse. If this is aFailureResult, returnstrue. - 
isFailureAnd(predicate: (error: TError) => boolean): booleanIf this is a
SuccessResult, returnsfalse. If this is aFailureResult, returns the result of applyingpredicateto the contained error. - 
isSuccess(): booleanIf this is a
SuccessResult, returnstrue. If this is aFailureResult, returnsfalse. - 
isSuccessAnd(predicate: (value: TValue) => boolean): booleanIf this is a
SuccessResult, returns the result of applyingpredicateto the contained value. If this is aFailureResult, returnsfalse. - 
map<TNewValue>(f: (value: TValue) => TNewValue): Result<TNewValue, TError>If this is a
SuccessResult, returns aSuccessResultcontaining the result of applyingfto the contained value. If this is aFailureResult, returns thisResult. - 
mapFailure<TNewError>(f: (error: TError) => TNewError): Result<TValue, TNewError>If this is a
SuccessResult, returns thisResult. If this is aFailureResult, returns aFailureResultcontaining the result of applyingfto the contained error. - 
or<TOtherError>(other: Result<TValue, TOtherError>): Result<TValue, TOtherError>If this is a
SuccessResult, returns thisResult. If this is aFailureResult, returnsother. - 
unwrap(): TValueIf this is a
SuccessResult, returns the contained value. If this is aFailureResult, throws anImproperUnwrapError. - 
unwrapFailure(): TErrorIf this is a
SuccessResult, throws anImproperUnwrapError. If this is aFailureResult, returns the contained error. 
The following examples illustrate some real-world scenarios where eaux can be useful.
Assume you want to process user input that might be empty. With Maybe, you can ensure that every code path explicitly checks whether the value exists.
import { nothing, something } from 'eaux'
// A function that simulates reading user input.
function getUserInput() {
  // Imagine a real implementation here.
  const randomNumber = Math.random()
  return (randomNumber > 0.5) ?
    'Hello, world!' :
    null
}
const input = getUserInput()
const maybeInput = (input !== null) ?
  something(input) :
  nothing()
if (maybeInput.isSomething()) {
  console.log('User input provided:', maybeInput.unwrap())
} else {
  console.log('No user input was provided')
}Imagine a routine that attempts to parse a string into a number. By using Result, you enforce error handling explicitly.
import { failure, success } from 'eaux'
function parseNumber(input: string): Result<number, string> {
  const parsedValue = Number(input)
  // Check for non-numeric values.
  if (isNaN(parsedValue)) {
    return failure('Invalid number format, expected a numeric string.')
  }
  return success(parsedValue)
}
const result = parseNumber('42') // Try changing `'42'` to an invalid input.
if (result.isSuccess()) {
  console.log('Number parsed:', result.unwrap())
} else {
  console.error('Error parsing number:', result.unwrapFailure())
}Combine operations using chainable methods to build complex logic that is both clear and explicit.
import { nothing, something } from 'eaux'
function doubleValue(value: number): number {
  return (value * 2)
}
const maybeValue = something(21)
// Chain the operations: if the value exists, double it; otherwise, do nothing.
const transformedValue = maybeValue
  .map(doubleValue)
  .or(something(0))
console.log('Value transformed:', transformedValue.unwrap())This project is licensed under the Apache License, Version 2.0. See the accompanying LICENSE file for details.