Maybe<T>
Maybe is used to represent a value that may or may not exist. It can either be a Just<T> or a Nothing.
| import { fromNullable } from 'holo-fn/maybe'
const name = fromNullable('Rich')
.map(n => n.toUpperCase())
.unwrapOr('Anonymous')
console.log(name) // RICH
|
Methods
map(fn: (value: T) => U): Maybe<U>
Maps over the Just value. Does nothing for Nothing.
| import { Just, Nothing } from "holo-fn/maybe";
const result1 = new Just(5).map((n) => n * 2);
console.log(result1.unwrapOr(0)); // 10
const result2 = new Nothing<number>().map((n) => n * 2);
console.log(result2.unwrapOr(0)); // 0
|
chain(fn: (value: T) => Maybe<U>): Maybe<U>
Chains the transformation if the value is Just. Returns Nothing otherwise.
| import { Just, Nothing } from "holo-fn/maybe";
const result1 = new Just(5).chain((n) => new Just(n * 2));
console.log(result1.unwrapOr(0)); // 10
const result2 = new Nothing<number>().chain((n) => new Just(n * 2));
console.log(result2.unwrapOr(0)); // 0
|
filter(fn: (value: T) => boolean): Maybe<T>
Filters the Just value based on a predicate. If the predicate returns true, keeps the value. If it returns false, converts to Nothing. Does nothing for Nothing.
| import { Just, Nothing } from "holo-fn/maybe";
const result1 = new Just(25).filter((n) => n >= 18);
console.log(result1.unwrapOr(0)); // 25
const result2 = new Just(15).filter((n) => n >= 18);
console.log(result2.unwrapOr(0)); // 0
const result3 = new Nothing<number>().filter((n) => n >= 18);
console.log(result3.unwrapOr(0)); // 0
|
unwrapOr(defaultValue: T): T
Returns the value of Just, or the default value for Nothing.
| import { Just, Nothing } from "holo-fn/maybe";
const result1 = new Just(10);
console.log(result1.unwrapOr(0)); // 10
const result2 = new Nothing<number>();
console.log(result2.unwrapOr(0)); // 0
|
isJust(): boolean
Checks if the value is Just.
| import { Just, Nothing } from "holo-fn/maybe";
const result1 = new Just("value");
console.log(result1.isJust()); // true
const result2 = new Nothing();
console.log(result2.isJust()); // false
|
isNothing(): boolean
Checks if the value is Nothing.
| import { Just, Nothing } from "holo-fn/maybe";
const result1 = new Just("value");
console.log(result1.isNothing()); // false
const result2 = new Nothing();
console.log(result2.isNothing()); // true
|
match<U>(cases: { just: (value: T) => U; nothing: () => U }): U
Matches the value to execute either the just or nothing case.
1
2
3
4
5
6
7
8
9
10
11
12
13 | import { Just, Nothing } from "holo-fn/maybe";
const result1 = new Just("value").match({
just: (v) => `Has value: ${v}`,
nothing: () => "No value",
});
console.log(result1); // "Has value: value"
const result2 = new Nothing().match({
just: (v) => `Has value: ${v}`,
nothing: () => "No value",
});
console.log(result2); // "No value"
|
equals(other: Maybe<T>): boolean
Compares the values inside this and the other, returns true if both are Nothing or if the values are equal.
| import type { Maybe } from "holo-fn";
import { Just, Nothing } from "holo-fn/maybe";
const result1 = new Just("value").chain(v => new Just(v + " modified"));
console.log(result1.equals(new Just("value"))); // false
console.log(result1.equals(new Just("value modified"))); // true
const result2: Maybe<string> = new Just("value").chain(v => new Nothing());
console.log(result2.equals(new Nothing())); // true
console.log(result2.equals(new Just("value"))); // false
|
Helpers
just(value: T): Maybe<T>
Creates a Just value with the given value, representing the presence of a value.
| import { just } from 'holo-fn/maybe';
const maybeValue = just('Hello');
console.log(maybeValue.unwrapOr('Default')); // 'Hello'
|
nothing<T = never>(): Maybe<T>
Creates a Nothing value, representing the absence of a value.
| import { nothing } from 'holo-fn/maybe';
const maybeValue = nothing<string>();
console.log(maybeValue.unwrapOr('Default')); // 'Default'
|
fromNullable(value)
Creates a Maybe from a value that might be null or undefined.
| const maybeEmail = fromNullable(user.email)
|
- Returns
Just<T> if the value is not null or undefined
- Returns
Nothing otherwise
Curried Helpers
map
Curried version of map for Maybe. This allows functional composition with pipe.
| import { Just, map } from 'holo-fn/maybe';
const result = pipe(
new Just(10),
map((x) => x * 2),
(res) => res.unwrapOr(0)
);
console.log(result); // 20
|
chain
Curried version of chain for Maybe. This allows chaining transformations in a functional pipeline.
| import { chain, Just } from 'holo-fn/maybe';
const result = pipe(
new Just(2),
chain((x) => new Just(x * 10)),
(res) => res.unwrapOr(0)
);
console.log(result); // 20
|
filter
Curried version of filter for Maybe. This allows filtering values in a functional pipeline based on a predicate.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 | import { filter, just } from 'holo-fn/maybe';
const result = pipe(
just(25),
filter((x) => x >= 18),
filter((x) => x <= 100),
(res) => res.unwrapOr(0)
);
console.log(result); // 25
// Validate age
const validateAge = (age: number) =>
pipe(
just(age),
filter((x) => x >= 0),
filter((x) => x <= 150),
filter((x) => x >= 18)
);
console.log(validateAge(151).unwrapOr(0)); // 25
// Validate email format
const validateEmail = (email: string) =>
pipe(
just(email),
filter((s) => s.length > 0),
filter((s) => s.includes('@')),
filter((s) => s.split('@')[1]?.includes('.') ?? false)
);
console.log(validateEmail('test@example.com').unwrapOr('Invalid email'));
// Parse positive integers
const parsePositive = (input: string) =>
pipe(
just(input),
map((s) => parseInt(s, 10)),
filter((n) => !isNaN(n)),
filter((n) => n > 0)
);
console.log(parsePositive('42').unwrapOr(0)); // 42
|
unwrapOr
Curried version of unwrapOr for Maybe. This provides a cleaner way to unwrap the value in a Maybe.
| import { Nothing, unwrapOr } from 'holo-fn/maybe';
const result = pipe(
new Nothing<string>(),
unwrapOr("No value")
);
console.log(result); // "No value"
|
match
Curried version of match for Maybe. This allows handling Just and Nothing in a functional way.
| import { Just, match } from 'holo-fn/maybe';
const result = pipe(
new Just("hello"),
match({
just: (v) => `Got ${v}`,
nothing: () => "No value"
})
);
console.log(result); // "Got hello"
|
equals
Curried version of equals for Maybe. Compares the values inside this and the other, returns true if both are Nothing or if the values are equal.
| import { equals, Just } from 'holo-fn/maybe';
const result = pipe(
new Just(10),
equals(new Just(10))
);
console.log(result); // true
|
all
Combines an array of Maybe values into a single Maybe containing an array. Returns Just with all values if all are Just, or Nothing if any is Nothing.
1
2
3
4
5
6
7
8
9
10
11
12
13 | import { all, just, nothing, type Maybe } from 'holo-fn/maybe';
// All success case
const result1: Maybe<number[]> = all([just(1), just(2), just(3)]);
console.log(result1.unwrapOr([])); // [1, 2, 3]
// Any failure case
const result2 = all([just(1), nothing(), just(3)]);
console.log(result2.isNothing()); // true
// Empty array
const result3 = all([]);
console.log(result3.unwrapOr([])); // []
|
Common Patterns
Combining multiple Maybes
When you need to work with multiple Maybe values:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | import { all, just, match } from 'holo-fn/maybe';
import { pipe } from 'rambda';
const name = just('Test User');
const age = just(25);
const email = just('testuser@example.com');
const user = pipe(
all([name, age, email]),
match({
just: ([n, a, e]) => ({ name: n, age: a, email: e }),
nothing: () => null,
})
);
console.log(user);
// Output: { name: 'Test User', age: 25, email: 'testuser@example.com' }
|
Conditional logic with predicates
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | import { just, match } from 'holo-fn/maybe';
import { pipe } from 'rambda';
const value = just(42);
const category = pipe(
value,
match({
just: (v) => {
if (v > 100) return 'big';
if (v > 50) return 'medium';
return 'small';
},
nothing: () => 'unknown',
})
);
console.log(`The number is categorized as: ${category}`);
|
Chaining operations with early exit
1
2
3
4
5
6
7
8
9
10
11
12
13 | import { chain, filter, fromNullable, map } from 'holo-fn/maybe';
import { pipe } from 'rambda';
const user: { email?: string } | null = { email: 'testuser@example.com' };
const result = pipe(
fromNullable(user),
chain((u) => fromNullable(u.email)),
filter((email) => email.includes('@')),
map((email) => email.toLowerCase())
);
console.log(result); // Just('testuser@example.com')
|