Skip to content

Maybe<Value>

The Maybe container may or may not hold some value. It is commonly used to represent optional values.

Maybe constructors

You can create a Maybe by calling the Some and None constructors.

ts
const aNumber = Maybe.Some(1);
const aNumber = Maybe.None();

You can also enforce their type for the Some type

ts
const aNumber = Maybe.Some<number>(1);

You can create a Maybe from a possible null or undefined type

ts
Maybe.fromNullable('Hello world!') // Some('Hello world')
Maybe.fromNullable(null) // None
Maybe.fromNullable(undefined) // None

Methods

The Maybe container exposes several methods for value manipulation

.map(fn)

ts
Maybe<T>.map<R>(fn: (input: T) => R): Maybe<R>

Transforms the value inside the maybe in case of Some and does nothing otherwise.

ts
const someValue = Maybe.Some(5);
const newValue = someValue.map(x => x * 2); // Some(10)

const noneValue = Maybe.None();
const unchangedValue = noneValue.map(x => x * 2); // None

.flatMap(fn)

ts
Maybe<T>.flatMap<R>(fn: (input: T) => Maybe<R>): Maybe<R>

Transforms the value inside the maybe into another Maybe and flattens the result.

ts
const someValue = Maybe.Some(5);
const newSome = someValue.flatMap(x => Maybe.Some(x * 2)); // Some(10)

const helloValue = Maybe.Some("Hello world!")
const newHello = helloValue.flatMap(s => s.length > 10 ? Maybe.None() : Maybe.Some("") ) // None

const noneValue = Maybe.None();
const unchangedNone = noneValue.flatMap(x => Maybe.Some(x * 2)); // None

.filter(fn)

ts
Maybe<T>.filter(predicate: (input: T) => boolean): Maybe<T>

Filters the value inside the maybe based on a predicate function.

ts
const someValue = Maybe.Some(5);
const filteredValue = someValue.filter(x => x > 3); // Some(5)
const noneFilteredValue = someValue.filter(x => x < 3); // None

const noneValue = Maybe.None();
const unchangedValue = noneValue.filter(x => x > 3); // None

.isPresent()

ts
Maybe<T>.isPresent(): boolean

Checks if the Maybe contains a value.

ts
const someValue = Maybe.Some(5);
console.log(someValue.isPresent()); // true

const noneValue = Maybe.None();
console.log(noneValue.isPresent()); // false

.isEmpty()

ts
Maybe<T>.isEmpty(): boolean

Checks if the Maybe is empty.

ts
const someValue = Maybe.Some(5);
console.log(someValue.isEmpty()); // false

const noneValue = Maybe.None();
console.log(noneValue.isEmpty()); // true

.match()

ts
Maybe<T>.match<S,N>(matcher: {Some: (input: T) => S, None: N}): S | N
Maybe<T>.match<S,N>(matcher: {Some: S, None: N}): S | N

Matches the Maybe to a function or value based on its state (Some or None). This allows handling both states of the Maybe in a single call.

ts
const someValue = Maybe.Some(5);
const result = someValue.match({
    Some: x => `Value is ${x}`,
    None: 'No value'
}); // "Value is 5"

const noneValue = Maybe.None();
const resultNone = noneValue.match({
    Some: x => `Value is ${x}`,
    None: 'No value'
}); // "No value"

If you your Some operation does not depend on the maybe value you can do, for example

ts
const someValue = Maybe.Some(5);
const result = someValue.match({
    Some: true,
    None: false
}); // true

.ifPresent(fn)

ts
Maybe<T>.ifPresent(fn: (input: T) => any): Maybe<T>

Applies a function to the value inside the Maybe if it is Some, does nothing otherwise.

ts
const someValue = Maybe.Some(5);
someValue.ifPresent(x => console.log(x)); // Logs: 5

const noneValue = Maybe.None();
noneValue.ifPresent(x => console.log(x)); // Does nothing

.getWithDefault(defaultValue)

ts
Maybe<T>.getWithDefault<R>(defaultValue: R): T | R

Returns the value inside the Maybe if it is Some, otherwise returns the default value.

ts
const someValue = Maybe.Some(5);
console.log(someValue.getWithDefault(10)); // 5

const noneValue = Maybe.None();
console.log(noneValue.getWithDefault(10)); // 10

.unwrap()

ts
Maybe<T>.unwrap()

Returns the value inside the Maybe if it is Some.

ts
const maybe = Maybe.fromNullable("Hello world!");
const value = maybe.unwrap();  // does not compile!

if (maybe.isSome()) {
  const value = maybe.unwrap(); // Hello world!
}