Maybe encapsulates the idea of a value that might not be there.
A Maybe value can either be Just some value or Nothing.
type Maybe<T> = Just<T> | Nothing;Where Nothing is an instance of Nothing, null or undefined, and Just represents any non Nothing value.
If this is new to you, you may want to read the introductory article Safer code with container types about why and how to use this library.
npm install ts.data.maybe --save
import { Maybe, just, withDefault, map2 } from 'ts.data.maybe';
interface User {
email: string;
name: Maybe<string>;
surname: Maybe<string>;
}
const user: User = {
email: 'user@example.com',
name: just('John'),
surname: just('Doe')
};
const getFullName = (name: string, surname: string) => `${name} ${surname}`;
const maybeFullname = map2(getFullName, user.name, user.surname); // Just<string>('John Doe')
console.log(withDefault(maybeFullname, '')); // 'John Doe'const prices: Maybe<number>[] = [
just(300),
nothing(),
just(500),
just(150),
nothing()
];
const sum = (a: number, b: number) => a + b;
const total = prices
.filter(n => !equals(n, nothing()))
.reduce((acc, current) => map2(sum, acc, current), just(0));
console.log(withDefault(total, 0)); // 950(Inspired by elm-lang)
just<T>(value: T): Maybe<T>;
Wraps a value in an instance of Just.
just(5); // Just(5) (Maybe<number>)nothing<T>(): Maybe<T>;
Creates an instance of Nothing.
nothing<number>(); // Nothing (Maybe<number>)It's recommended to parametrize the function, otherwise the resolved type will be
Maybe<unknown>and type won't flow throughmap,andThenand so on.
isJust<T>(value: Maybe<T>): value is Just<T>;
Returns true if a value is an instance of Just.
isJust(nothing()); // falseisNothing<T>(value: Maybe<T>): value is Nothing;
Returns true if a value is an instance of Nothing.
isNothing(just(5)); // false
isNothing(undefined); // true
isNothing(null); // true
isNothing(nothing()); // truewithDefault<A>(value: Maybe<A>, defaultValue: A): A;
If value is an instance of Just it returns its wrapped value, if it's an instance of Nothing it returns the defaultValue.
withDefault(just(5), 0); // 5
withDefault(nothing(), 'hola'); // 'hola'caseOf<A, B>(caseof: {Just: (v: A) => B; Nothing: () => B;}, value: Maybe<A>): B;
Run different computations depending on whether a Maybe is Just or Nothing and returns the result.
caseOf(
{
Nothing: () => 'Do nothing',
Just: n => `Launch ${n} missiles`
},
just(5)
); // 'Launch 5 missiles'map<A, B>(f: (a: A) => B, value: Maybe<A>): Maybe<B>;
Transforms a Maybe value with a given function.
const add1 = (n: number) => n + 1;
map(add1, just(4)); // Just<number>(5)
map(add1, nothing()); // NothingThere are map2, map3, map4, map5 and mapN functions too:
map2<A, B, C>(
f: (a: A, b: B) => C,
a: Maybe<A>, b: Maybe<B>
): Maybe<C>An example with map2:
const safeParseInt = (num: string): Maybe<number> => {
const n = parseInt(num, 10);
return isNaN(n) ? nothing() : just(n);
};
const sum = (x: number, y: number) => x + y;
const safeStringSum = (x: string, y: string) =>
map2(sum, safeParseInt(x), safeParseInt(y));
safeStringSum('1', '2'); // Just<number>(3)
safeStringSum('a', '2'); // NothingIf you need to parametrize the function with more than one argument, use the map that matches your parametrization.
mapNonly accepts arguments of the same type)
map3<A, B, C, D>(
f: (a: A, b: B, c: C) => D,
a: Maybe<A>, b: Maybe<B>, c: Maybe<C>
): Maybe<D>map4<A, B, C, D, E>(
f: (a: A, b: B, c: C, d: D) => E,
a: Maybe<A>, b: Maybe<B>, c: Maybe<C>, d: Maybe<D>
): Maybe<E>map5<A, B, C, D, E, F>(
f: (a: A, b: B, c: C, d: D, e: E) => F,
a: Maybe<A>, b: Maybe<B>, c: Maybe<C>, d: Maybe<D>, e: Maybe<E>
): Maybe<F>mapN<A, B>(
f: (...a: A[]) => B,
...a: Maybe<A>[]
): Maybe<B>andThen<A, B>(f: (a: A) => Maybe<B>, v: Maybe<A>): Maybe<B>;
Chains together many computations that may fail.
const head = (arr: string[]) => (arr.length > 0 ? just(arr[0]) : nothing());
andThen(head, just(['a', 'b', 'c'])); // Just<string>('a')
andThen(head, just([])); // Nothingequals<T>(a: Maybe<T>, b: Maybe<T>): boolean;
Compares two Maybe instances and returns true when both are Nothing or their wrapped values are strictly equal (===), false otherwise.
equals(just(5), just(5); // true
equals(just(6), just(5); // false
equals(nothing(), just(5); // false
equals(nothing(), nothing(); // true
equals(null, nothing(); // true
equals(undefined, nothing(); // true