Options
All
  • Public
  • Public/Protected
  • All
Menu

External module "maybe"

Maybe

A Maybe<T> represents a value of type T which may, or may not, be present.

If the value is present, it is Just(value). If it's absent, it's Nothing. This provides a type-safe container for dealing with the possibility that there's nothing here – a container you can do many of the same things you might with an array – so that you can avoid nasty null and undefined checks throughout your codebase.

The behavior of this type is checked by TypeScript or Flow at compile time, and bears no runtime overhead other than the very small cost of the container object and some lightweight wrap/unwrap functionality.

The Nothing variant has a type parameter <T> so that type inference works correctly in TypeScript when operating on Nothing instances with functions which require a T to behave properly, e.g. map, which cannot check that the map function satisfies the type constraints for Maybe<T> unless Nothing has a parameter T to constrain it on invocation.

Put simply: without the type parameter, if you had a Nothing variant of a Maybe<string>, and you tried to use it with a function which expected a Maybe<number> it would still type check – because TypeScript doesn't have enough information to check that it doesn't meet the requirements.

Using Maybe

The library is designed to be used with a functional style, allowing you to compose operations easily. Thus, standalone pure function versions of every operation are supplied. However, the same operations also exist on the Just and Nothing types directly, so you may also write them in a more traditional "fluent" object style.

Examples: functional style

import Maybe from 'true-myth/maybe';

// Construct a `Just` where you have a value to use, and the function accepts
// a `Maybe`.
const aKnownNumber = Maybe.just(12);

// Construct a `Nothing` where you don't have a value to use, but the
// function requires a value (and accepts a `Maybe`).
const aKnownNothing = Maybe.nothing<string>();

// Construct a `Maybe` where you don't know whether the value will exist or
// not, using `of`.
type WhoKnows = { mightBeAThing?: boolean[] };

const whoKnows: WhoKnows = {};
const wrappedWhoKnows = Maybe.of(whoKnows.mightBeAThing);
console.log(toString(wrappedWhoKnows)); // Nothing

const whoElseKnows: WhoKnows = { mightBeAThing: [true, false] };
const wrappedWhoElseKnows = Maybe.of(whoElseKnows.mightBeAThing);
console.log(toString(wrappedWhoElseKnows)); // "Just(true,false)"

Examples: fluent object invocation

Note: in the "class"-style, if you are constructing a Maybe from an unknown source, you must either do the work to check the value yourself, or use Maybe.of – you can't know at that point whether it's safe to construct a Just without checking, but of will always work correctly!

import { isVoid } from 'true-myth/utils';
import Maybe, { Just, Nothing } from 'true-myth/maybe';

// Construct a `Just` where you have a value to use, and the function accepts
// a `Maybe`.
const aKnownNumber = new Just(12);

// Once the item is constructed, you can apply methods directly on it.
const fromMappedJust = aKnownNumber.map(x => x * 2).unwrapOr(0);
console.log(fromMappedJust); // 24

// Construct a `Nothing` where you don't have a value to use, but the
// function requires a value (and accepts a `Maybe<string>`).
const aKnownNothing = new Nothing();

// The same operations will behave safely on a `Nothing` as on a `Just`:
const fromMappedNothing = aKnownNothing.map(x => x * 2).unwrapOr(0);
console.log(fromMappedNothing); // 0

// Construct a `Maybe` where you don't know whether the value will exist or
// not, using `isVoid` to decide which to construct.
type WhoKnows = { mightBeAThing?: boolean[] };

const whoKnows: WhoKnows = {};
const wrappedWhoKnows = !isVoid(whoKnows.mightBeAThing)
  ? new Just(whoKnows.mightBeAThing)
  : new Nothing();

console.log(wrappedWhoKnows.toString()); // Nothing

const whoElseKnows: WhoKnows = { mightBeAThing: [true, false] };
const wrappedWhoElseKnows = !isVoid(whoElseKnows.mightBeAThing)
  ? new Just(whoElseKnows.mightBeAThing)
  : new Nothing();

console.log(wrappedWhoElseKnows.toString()); // "Just(true,false)"

As you can see, it's often advantageous to use Maybe.of even if you're otherwise inclined to use the class method approach; it dramatically cuts down the boilerplate you have to write (since, under the hood, it's doing exactly this check!).

Prefer Maybe.of

In fact, if you're dealing with data you are not constructing directly yourself, always prefer to use [Maybe.of] to create a new Maybe. If an API lies to you for some reason and hands you an undefined or a null (even though you expect it to be an actual T in a specific scenario), the .of() function will still construct it correctly for you.

By contrast, if you do Maybe.just(someVariable) and someVariable is null or undefined, the program will throw at that point. This is a simple consequence of the need to make the new Just() constructor work; we cannot construct Just safely in a way that excludes a type of Maybe<null> or Maybe<undefined> otherwise – and that would defeat the whole purpose of using a Maybe!

Writing type constraints

Especially when constructing a Nothing, you may need to specify what kind of Nothing it is. The TypeScript and Flow type systems can figure it out based on the value passed in for a Just, but there's no value to use with a Nothing, so you may have to specify it. In that case, you can write the type explicitly:

import Maybe, { nothing } from 'true-myth/maybe';

function takesAMaybeString(thingItTakes: Maybe<string>) {
  console.log(thingItTakes.unwrapOr(''));
}

// Via type definition
const nothingHere: Maybe<string> = nothing();
takesAMaybeString(nothingHere);

// Via type coercion
const nothingHereEither = nothing<string>();
takesAMaybeString(nothingHereEither);

Note that this is necessary if you declare the Maybe in a statement inside a function, but is not necessary when you have an expression-bodied arrow function or when you return the item directly:

import Maybe, { nothing } from 'true-myth/maybe';

// ERROR: Type 'Maybe<{}>' is not assignable to type 'Maybe<number>'.
const getAMaybeNotAssignable = (): Maybe<number> => {
  const theMaybe = nothing();
  return theMaybe;
};

// Succeeds
const getAMaybeExpression = (shouldBeJust: boolean): Maybe<number> => nothing();

// Succeeds
const getAMaybeReturn = (shouldBeJust: boolean): Maybe<number> => {
  return nothing();
};

Using Maybe Effectively

The best times to create and safely unwrap Maybes are at the boundaries of your application. When you are deserializing data from an API, or when you are handling user input, you can use a Maybe instance to handle the possibility that there's just nothing there, if there is no good default value to use everywhere in the application. Within the business logic of your application, you can then safely deal with the data by using the Maybe functions or method until you hit another boundary, and then you can choose how best to handle it at that point.

You won't normally need to unwrap it at any point other than the boundaries, because you can simply apply any transformations using the helper functions or methods, and be confident that you'll have either correctly transformed data, or a Nothing, at the end, depending on your inputs.

If you are handing data off to another API, for example, you might convert a Nothing right back into a null in a JSON payload, as that's a reasonable way to send the data across the wire – the consumer can then decide how to handle it as is appropriate in its own context.

If you are rendering a UI, having a Nothing when you need to render gives you an opportunity to provide default/fallback content – whether that's an explanation that there's nothing there, or a sensible substitute, or anything else that might be appropriate at that point in your app.

You may also be tempted to use Maybes to replace boolean flags or similar approaches for defining branching behavior or output from a function. You should avoid that, in general. Reserve Maybe for modeling the possible absence of data, and nothing else. Prefer to use Result or Either for fallible or disjoint scenarios instead – or construct your own union types if you have more than two boundaries!

Finally, and along similar lines, if you find yourself building a data structure with a lot of Maybe types in it, you should consider it a "code smell" – something wrong with your model. It usually means you should find a way to refactor the data structure into a union of smaller data structures which more accurately capture the domain you're modeling.

Index

Type aliases

All

All: All<T>

Matcher

Matcher: object

A lightweight object defining how to handle each variant of a Maybe.

Type declaration

  • Just: function
      • (value: T): NonNullable<A>
      • Parameters

        • value: T

        Returns NonNullable<A>

  • Nothing: function
      • (): A
      • Returns A

MaybeJSON

MaybeJSON: JustJSON<T> | NothingJSON

Predicate

Predicate: function

Type declaration

    • (element: T, index: number, array: T[]): boolean
    • Parameters

      • element: T
      • index: number
      • array: T[]

      Returns boolean

Variables

Let NOTHING

NOTHING: Nothing<any>

Const cata

cata: match = match

Alias for match

Const chain

chain: andThen = andThen

Alias for andThen.

Const first

first: head = head

A convenience alias for Maybe.head.

Const flatMap

flatMap: andThen = andThen

Alias for andThen.

Const fromNullable

fromNullable: of = of

Alias for of, primarily for compatibility with Folktale.

Const getOr

getOr: unwrapOr = unwrapOr

Alias for unwrapOr

Const getOrElse

getOrElse: unwrapOrElse = unwrapOrElse

Alias for unwrapOrElse

Const maybeify

maybeify: wrapReturn = wrapReturn

Alias for wrapReturn.

Const transmogrify

transmogrify: wrapReturn = wrapReturn

Const unsafeGet

unsafeGet: unsafelyUnwrap = unsafelyUnwrap

Alias for unsafelyUnwrap

Const unsafelyGet

unsafelyGet: unsafelyUnwrap = unsafelyUnwrap

Alias for unsafelyUnwrap

Functions

all

  • all<T>(...maybes: T): All<T>
  • Convert the arguments to a single Maybe. Useful for dealing with arrays of Maybes, via the spread operator.

    Examples

    import Maybe from 'true-myth/maybe';
    
    let valid = [Maybe.just(2), Maybe.just('three')];
    Maybe.all(...valid); // => Just([2, 'three']);
    
    let invalid = [Maybe.just(2), Maybe.nothing<string>()];
    Maybe.all(...invalid); // => Nothing

    Note on Spread

    This requires the use of the spread operator because (at least as of TypeScript 3.0), the type inference falls down when attempting to build this same type with an array directly. Moreover, this spread-based approach handles heteregenous arrays; TS also fails to infer correctly for anything but homogeneous arrays when using that approach.

    Type parameters

    Parameters

    • Rest ...maybes: T

      The Maybes to resolve to a single Maybe.

    Returns All<T>

and

  • You can think of this like a short-circuiting logical "and" operation on a Maybe type. If maybe is Just, then the result is the andMaybe. If maybe is Nothing, the result is Nothing.

    This is useful when you have another Maybe value you want to provide if and only if* you have a Just – that is, when you need to make sure that if you Nothing, whatever else you're handing a Maybe to also gets a Nothing.

    Notice that, unlike in map or its variants, the original maybe is not involved in constructing the new Maybe.

    Examples

    import Maybe from 'true-myth/maybe';
    
    const justA = Maybe.just('A');
    const justB = Maybe.just('B');
    const nothing: Maybe<number> = nothing();
    
    console.log(Maybe.and(justB, justA).toString());  // Just(B)
    console.log(Maybe.and(justB, nothing).toString());  // Nothing
    console.log(Maybe.and(nothing, justA).toString());  // Nothing
    console.log(Maybe.and(nothing, nothing).toString());  // Nothing

    Type parameters

    • T

      The type of the initial wrapped value.

    • U

      The type of the wrapped value of the returned Maybe.

    Parameters

    • andMaybe: Maybe<U>

      The Maybe instance to return if maybe is Just

    • maybe: Maybe<T>

      The Maybe instance to check.

    Returns Maybe<U>

    Nothing if the original maybe is Nothing, or andMaybe if the original maybe is Just.

  • Type parameters

    • T

    • U

    Parameters

    Returns function

andThen

  • andThen<T, U>(thenFn: function, maybe: Maybe<T>): Maybe<U>
  • andThen<T, U>(thenFn: function): function
  • Apply a function to the wrapped value if Just and return a new Just containing the resulting value; or return Nothing if Nothing.

    This differs from map in that thenFn returns another Maybe. You can use andThen to combine two functions which both create a Maybe from an unwrapped type.

    You may find the .then method on an ES6 Promise helpful for b: if you have a Promise, you can pass its then method a callback which returns another Promise, and the result will not be a nested promise, but a single Promise. The difference is that Promise#then unwraps all layers to only ever return a single Promise value, whereas Maybe.andThen will not unwrap nested Maybes.

    This is also commonly known as (and therefore aliased as) flatMap or chain. It is sometimes also known as bind, but not aliased as such because bind already means something in JavaScript.

    Example

    (This is a somewhat contrived example, but it serves to show the way the function behaves.)

    import Maybe from 'true-myth/maybe';
    
    // string -> Maybe<number>
    const toMaybeLength = (s: string): Maybe<number> => Maybe.of(s.length);
    
    // Maybe<string>
    const aMaybeString = Maybe.of('Hello, there!');
    
    // Maybe<number>
    const resultingLength = Maybe.andThen(toMaybeLength, aMaybeString);
    console.log(Maybe.toString(resultingLength)); // 13

    Note that the result is not (Just(13)), but 13!

    Type parameters

    • T

      The type of the wrapped value.

    • U

      The type of the wrapped value in the resulting Maybe.

    Parameters

    • thenFn: function

      The function to apply to the wrapped T if maybe is Just.

        • Parameters

          • t: T

          Returns Maybe<U>

    • maybe: Maybe<T>

      The Maybe to evaluate and possibly apply a function to the contents of.

    Returns Maybe<U>

    The result of the thenFn (a new Maybe) if maybe is a Just, otherwise Nothing if maybe is a Nothing.

  • Type parameters

    • T

    • U

    Parameters

    • thenFn: function
        • Parameters

          • t: T

          Returns Maybe<U>

    Returns function

ap

  • ap<T, U>(maybeFn: Maybe<function>, maybe: Maybe<T>): Maybe<U>
  • ap<T, U>(maybeFn: Maybe<function>): function
  • Allows you to apply (thus ap) a value to a function without having to take either out of the context of their Maybes. This does mean that the transforming function is itself within a Maybe, which can be hard to grok at first but lets you do some very elegant things. For example, ap allows you to this:

    import { just, nothing } from 'true-myth/maybe';
    
    const one = just(1);
    const five = just(5);
    const none = nothing();
    
    const add = (a: number) => (b: number) => a + b;
    const maybeAdd = just(add);
    
    maybeAdd.ap(one).ap(five); // Just(6)
    maybeAdd.ap(one).ap(none); // Nothing
    maybeAdd.ap(none).ap(five) // Nothing

    Without Maybe.ap, you'd need to do something like a nested Maybe.match:

    import { just, nothing } from 'true-myth/maybe';
    
    const one = just(1);
    const five = just(5);
    const none = nothing();
    
    one.match({
    Just: n => five.match({
    Just: o => just(n + o),
    Nothing: () => nothing(),
    }),
    Nothing: ()  => nothing(),
    }); // Just(6)
    
    one.match({
    Just: n => none.match({
    Just: o => just(n + o),
    Nothing: () => nothing(),
    }),
    Nothing: ()  => nothing(),
    }); // Nothing
    
    none.match({
    Just: n => five.match({
    Just: o => just(n + o),
    Nothing: () => nothing(),
    }),
    Nothing: ()  => nothing(),
    }); // Nothing

    And this kind of thing comes up quite often once you're using Maybe to handle optionality throughout your application.

    For another example, imagine you need to compare the equality of two ImmutableJS data structures, where a === comparison won't work. With ap, that's as simple as this:

    import Maybe from 'true-myth/maybe';
    import Immutable from 'immutable';
    import { curry } from 'lodash'
    
    const is = curry(Immutable.is);
    
    const x = Maybe.of(Immutable.Set.of(1, 2, 3));
    const y = Maybe.of(Immutable.Set.of(2, 3, 4));
    
    Maybe.of(is).ap(x).ap(y); // Just(false)

    Without ap, we're back to that gnarly nested match:

    import Maybe, { just, nothing } from 'true-myth/maybe';
    import Immutable from 'immutable';
    import { curry } from 'lodash'
    
    const is = curry(Immutable.is);
    
    const x = Maybe.of(Immutable.Set.of(1, 2, 3));
    const y = Maybe.of(Immutable.Set.of(2, 3, 4));
    
    x.match({
    Just: iX => y.match({
    Just: iY => Maybe.just(Immutable.is(iX, iY)),
    Nothing: () => Maybe.nothing(),
    })
    Nothing: () => Maybe.nothing(),
    }); // Just(false)

    In summary: anywhere you have two Maybe instances and need to perform an operation that uses both of them, ap is your friend.

    Two things to note, both regarding currying:

    1. All functions passed to ap must be curried. That is, they must be of the form (for add) (a: number) => (b: number) => a + b, not the more usual (a: number, b: number) => a + b you see in JavaScript more generally.

    For convenience, you may want to look at Lodash's _.curry or Ramda's R.curry, which allow you to create curried versions of functions whenever you want:

    import Maybe from 'true-myth/maybe';
    import { curry } from 'lodash';
    
    const normalAdd = (a: number, b: number) => a + b;
    const curriedAdd = curry(normalAdd); // (a: number) => (b: number) => a + b;
    
    Maybe.of(curriedAdd).ap(Maybe.of(1)).ap(Maybe.of(5)); // Just(6)
    1. You will need to call ap as many times as there are arguments to the function you're dealing with. So in the case of add, which has the "arity" (function argument count) of 2 (a and b), you'll need to call ap twice: once for a, and once for b. To see why, let's look at what the result in each phase is:
    const add = (a: number) => (b: number) => a + b;
    
    const maybeAdd = Maybe.of(add); // Just((a: number) => (b: number) => a + b)
    const maybeAdd1 = maybeAdd.ap(Maybe.of(1)); // Just((b: number) => 1 + b)
    const final = maybeAdd1.ap(Maybe.of(3)); // Just(4)

    So for toString, which just takes a single argument, you would only need to call ap once.

    const toStr = (v: { toString(): string }) => v.toString();
    Maybe.of(toStr).ap(12); // Just("12")

    One other scenario which doesn't come up quite as often but is conceivable is where you have something that may or may not actually construct a function for handling a specific Maybe scenario. In that case, you can wrap the possibly-present in ap and then wrap the values to apply to the function to in Maybe themselves.

    Aside:* ap is not named apply because of the overlap with JavaScript's existing apply function – and although strictly speaking, there isn't any direct overlap (Maybe.apply and Function.prototype.apply don't intersect at all) it's useful to have a different name to avoid implying that they're the same.

    Type parameters

    • T

    • U

    Parameters

    • maybeFn: Maybe<function>

      maybe a function from T to U

    • maybe: Maybe<T>

      maybe a T to apply to fn

    Returns Maybe<U>

  • Type parameters

    • T

    • U

    Parameters

    • maybeFn: Maybe<function>

    Returns function

equals

  • equals<T>(mb: Maybe<T>, ma: Maybe<T>): boolean
  • equals<T>(mb: Maybe<T>): function
  • Allows quick triple-equal equality check between the values inside two maybes without having to unwrap them first.

    const a = Maybe.of(3);
    const b = Maybe.of(3);
    const c = Maybe.of(null);
    const d = Maybe.nothing();
    
    Maybe.equals(a, b); // true
    Maybe.equals(a, c); // false
    Maybe.equals(c, d); // true

    Type parameters

    • T

    Parameters

    • mb: Maybe<T>

      A maybe to compare to.

    • ma: Maybe<T>

      A maybe instance to check.

    Returns boolean

  • Type parameters

    • T

    Parameters

    Returns function

      • (ma: Maybe<T>): boolean
      • Parameters

        Returns boolean

find

  • Safely search for an element in an array.

    This function behaves like Array.prototype.find, but returns Maybe<T> instead of T | undefined.

    Examples

    The basic form is:

    import Maybe from 'true-myth/maybe';
    
    let array = [1, 2, 3];
    Maybe.find(v => v > 1, array); // Just(2)
    Maybe.find(v => v < 1, array); // Nothing

    The function is curried so you can use it in a functional chain. For example (leaving aside error handling on a bad response for simplicity), suppose the url https://arrays.example.com returned a JSON payload with the type Array<{ count: number, name: string }>, and we wanted to get the first of these where count was at least 100. We could write this:

    import Maybe from 'true-myth/maybe';
    
    type Item = { count: number; name: string };
    type Response = Array<Item>;
    
    // curried variant!
    const findAtLeast100 = Maybe.find(({ count }: Item) => count > 100);
    
    fetch('https://arrays.example.com')
    .then(response => response.json() as Response)
    .then(findAtLeast100)
    .then(found => {
    if (found.isJust()) {
    console.log(`The matching value is ${found.value.name}!`);
    }
    });

    Type parameters

    • T

    Parameters

    • predicate: Predicate<T>

      A function to execute on each value in the array, returning true when the item in the array matches the condition. The signature for predicate is identical to the signature for the first argument to Array.prototype.find. The function is called once for each element of the array, in ascending order, until it finds one where predicate returns true. If such an element is found, find immediately returns that element value wrapped in Just. Otherwise, Maybe.find returns Nothing.

    • array: T[]

      The array to search using the predicate.

    Returns Maybe<T>

  • Type parameters

    • T

    Parameters

    Returns function

      • Parameters

        • array: T[]

        Returns Maybe<T>

fromResult

  • Construct a Maybe<T> from a Result<T, E>.

    If the Result is an Ok, wrap its value in Just. If the Result is an Err, throw away the wrapped E and transform to a Nothing.

    Type parameters

    • T

      The type of the value wrapped in a Result.Ok and in the Just of the resulting Maybe.

    Parameters

    • result: Result<T, any>

      The Result to construct a Maybe from.

    Returns Maybe<T>

    Just if result was Ok or Nothing if it was Err.

get

  • get<T, K>(key: K, maybeObj: Maybe<T>): Maybe<NonNullable<T[K]>>
  • get<T, K>(key: K): function
  • Safely extract a key from a Maybe of an object, returning Just if the key has a value on the object and Nothing if it does not. (Like Maybe.property but operating on a Maybe<T> rather than directly on a T.)

    The check is type-safe: you won't even be able to compile if you try to look up a property that TypeScript knows doesn't exist on the object.

    type Person = { name?: string };
    
    const me: Maybe<Person> = Maybe.just({ name: 'Chris' });
    console.log(Maybe.get('name', me)); // Just('Chris')
    
    const nobody = Maybe.nothing<Person>();
    console.log(Maybe.get('name', nobody)); // Nothing

    However, it also works correctly with dictionary types:

    type Dict<T> = { [key: string]: T };
    
    const score: Maybe<Dict<number>> = Maybe.just({
    player1: 0,
    player2: 1
    });
    
    console.log(Maybe.get('player1', score)); // Just(0)
    console.log(Maybe.get('player2', score)); // Just(1)
    console.log(Maybe.get('player3', score)); // Nothing

    The order of keys is so that it can be partially applied:

    type Person = { name?: string };
    
    const lookupName = Maybe.get('name');
    
    const me: Person = { name: 'Chris' };
    console.log(lookupName(me)); // Just('Chris')
    
    const nobody: Person = {};
    console.log(lookupName(nobody)); // Nothing

    Type parameters

    • T

    • K: keyof T

    Parameters

    • key: K

      The key to pull out of the object.

    • maybeObj: Maybe<T>

    Returns Maybe<NonNullable<T[K]>>

  • Type parameters

    • T

    • K: keyof T

    Parameters

    • key: K

    Returns function

      • Parameters

        Returns Maybe<NonNullable<T[K]>>

head

  • head<T>(array: Array<T | null | undefined>): Maybe<T>
  • Safely get the first item from a list, returning Just the first item if the array has at least one item in it, or Nothing if it is empty.

    Examples

    let empty = [];
    Maybe.head(empty); // => Nothing
    
    let full = [1, 2, 3];
    Maybe.head(full); // => Just(1)

    Type parameters

    • T

    Parameters

    • array: Array<T | null | undefined>

      The array to get the first item from.

    Returns Maybe<T>

isInstance

  • isInstance<T>(item: any): boolean
  • Determine whether an item is an instance of Just or Nothing.

    Type parameters

    • T

    Parameters

    • item: any

      The item to check.

    Returns boolean

isJust

  • isJust<T>(maybe: Maybe<T>): boolean
  • Is this result a Just instance?

    Type parameters

    • T

      The type of the wrapped value.

    Parameters

    • maybe: Maybe<T>

      The Maybe instance to check.

    Returns boolean

    true if maybe is Just, false otherwise. In TypeScript, also narrows the type from Maybe<T> to Just<T>.

isNothing

  • isNothing<T>(maybe: Maybe<T>): boolean
  • Is this result a Nothing instance?

    Type parameters

    • T

      The type of the wrapped value.

    Parameters

    • maybe: Maybe<T>

      The Maybe instance to check.

    Returns boolean

    true if maybe is nothing, false otherwise. In TypeScript, also narrows the type from Maybe<T> to Nothing<T>.

just

  • just<T>(value?: T | null): Maybe<T>
  • Create an instance of Maybe.Just.

    null and undefined are allowed by the type signature so that the function may throw on those rather than constructing a type like Maybe<undefined>.

    throws

    If you pass null or undefined.

    Type parameters

    • T

      The type of the item contained in the Maybe.

    Parameters

    • Optional value: T | null

      The value to wrap in a Maybe.Just.

    Returns Maybe<T>

    An instance of Maybe.Just<T>.

last

  • last<T>(array: Array<T | null | undefined>): Maybe<T>
  • Safely get the last item from a list, returning Just the last item if the array has at least one item in it, or Nothing if it is empty.

    Examples

    let empty = [];
    Maybe.last(empty); // => Nothing
    
    let full = [1, 2, 3];
    Maybe.last(full); // => Just(3)

    Type parameters

    • T

    Parameters

    • array: Array<T | null | undefined>

      The array to get the first item from.

    Returns Maybe<T>

map

  • map<T, U>(mapFn: function): function
  • map<T, U>(mapFn: function, maybe: Maybe<T>): Maybe<U>
  • Map over a Maybe instance: apply the function to the wrapped value if the instance is Just, and return Nothing if the instance is Nothing.

    Maybe.map works a lot like Array.prototype.map: Maybe and Array are both containers for other things. If you have no items in an array of numbers named foo and call foo.map(x => x + 1), you'll still just have an array with nothing in it. But if you have any items in the array ([2, 3]), and you call foo.map(x => x + 1) on it, you'll get a new array with each of those items inside the array "container" transformed ([3, 4]).

    That's exactly what's happening with Maybe.map. If the container is empty – the Nothing variant – you just get back an empty container. If the container has something in it – the Just variant – you get back a container with the item inside transformed.

    (So... why not just use an array? The biggest reason is that an array can be any length. With a Maybe, we're capturing the idea of "something or nothing" rather than "0 to n" items. And this lets us implement a whole set of other interfaces, like those in this module.)

    Examples

    const length = (s: string) => s.length;
    
    const justAString = Maybe.just('string');
    const justTheStringLength = map(length, justAString);
    console.log(justTheStringLength.toString()); // Just(6)
    
    const notAString = Maybe.nothing<string>();
    const notAStringLength = map(length, notAString);
    console.log(notAStringLength.toString()); // "Nothing"

    Type parameters

    • T

      The type of the wrapped value.

    • U

      The type of the wrapped value of the returned Maybe.

    Parameters

    • mapFn: function

      The function to apply the value to if Maybe is Just.

        • (t: T): NonNullable<U>
        • Parameters

          • t: T

          Returns NonNullable<U>

    Returns function

    A new Maybe with the result of applying mapFn to the value in a Just, or Nothing if maybe is Nothing.

      • Parameters

        • maybe: Maybe<T>

          The Maybe instance to map over.

        Returns Maybe<U>

  • Type parameters

    • T

    • U

    Parameters

    • mapFn: function
        • (t: T): NonNullable<U>
        • Parameters

          • t: T

          Returns NonNullable<U>

    • maybe: Maybe<T>

    Returns Maybe<U>

mapOr

  • mapOr<T, U>(orU: U, mapFn: function, maybe: Maybe<T>): U
  • mapOr<T, U>(orU: U, mapFn: function): function
  • mapOr<T, U>(orU: U): function
  • Map over a Maybe instance and get out the value if maybe is a Just, or return a default value if maybe is a Nothing.

    Examples

    const length = (s: string) => s.length;
    
    const justAString = Maybe.just('string');
    const theStringLength = mapOr(0, length, justAString);
    console.log(theStringLength); // 6
    
    const notAString = Maybe.nothing<string>();
    const notAStringLength = mapOr(0, length, notAString)
    console.log(notAStringLength); // 0

    Type parameters

    • T

      The type of the wrapped value.

    • U

      The type of the wrapped value of the returned Maybe.

    Parameters

    • orU: U

      The default value to use if maybe is Nothing

    • mapFn: function

      The function to apply the value to if Maybe is Just

        • (t: T): NonNullable<U>
        • Parameters

          • t: T

          Returns NonNullable<U>

    • maybe: Maybe<T>

      The Maybe instance to map over.

    Returns U

  • Type parameters

    • T

    • U

    Parameters

    • orU: U
    • mapFn: function
        • (t: T): NonNullable<U>
        • Parameters

          • t: T

          Returns NonNullable<U>

    Returns function

      • Parameters

        Returns U

  • Type parameters

    • T

    • U

    Parameters

    • orU: U

    Returns function

      • (mapFn: function): function
      • Parameters

        • mapFn: function
            • (t: T): NonNullable<U>
            • Parameters

              • t: T

              Returns NonNullable<U>

        Returns function

          • Parameters

            Returns U

mapOrElse

  • mapOrElse<T, U>(orElseFn: function, mapFn: function, maybe: Maybe<T>): U
  • mapOrElse<T, U>(orElseFn: function, mapFn: function): function
  • mapOrElse<T, U>(orElseFn: function): function
  • Map over a Maybe instance and get out the value if maybe is a Just, or use a function to construct a default value if maybe is Nothing.

    Examples

    const length = (s: string) => s.length;
    const getDefault = () => 0;
    
    const justAString = Maybe.just('string');
    const theStringLength = mapOrElse(getDefault, length, justAString);
    console.log(theStringLength); // 6
    
    const notAString = Maybe.nothing<string>();
    const notAStringLength = mapOrElse(getDefault, length, notAString)
    console.log(notAStringLength); // 0

    Type parameters

    • T

      The type of the wrapped value.

    • U

      The type of the wrapped value of the returned Maybe.

    Parameters

    • orElseFn: function

      The function to apply if maybe is Nothing.

        • (): U
        • Returns U

    • mapFn: function

      The function to apply to the wrapped value if maybe is Just

        • (t: T): NonNullable<U>
        • Parameters

          • t: T

          Returns NonNullable<U>

    • maybe: Maybe<T>

      The Maybe instance to map over.

    Returns U

  • Type parameters

    • T

    • U

    Parameters

    • orElseFn: function
        • (): U
        • Returns U

    • mapFn: function
        • (t: T): NonNullable<U>
        • Parameters

          • t: T

          Returns NonNullable<U>

    Returns function

      • Parameters

        Returns U

  • Type parameters

    • T

    • U

    Parameters

    • orElseFn: function
        • (): U
        • Returns U

    Returns function

      • (mapFn: function): function
      • Parameters

        • mapFn: function
            • (t: T): NonNullable<U>
            • Parameters

              • t: T

              Returns NonNullable<U>

        Returns function

          • Parameters

            Returns U

match

  • match<T, A>(matcher: Matcher<T, A>, maybe: Maybe<T>): A
  • match<T, A>(matcher: Matcher<T, A>): function
  • Performs the same basic functionality as getOrElse, but instead of simply unwrapping the value if it is Just and applying a value to generate the same default type if it is Nothing, lets you supply functions which may transform the wrapped type if it is Just or get a default value for Nothing.

    This is kind of like a poor man's version of pattern matching, which JavaScript currently lacks.

    Instead of code like this:

    import Maybe from 'true-myth/maybe';
    
    const logValue = (mightBeANumber: Maybe<number>) => {
    const valueToLog = Maybe.mightBeANumber.isJust()
    ? Maybe.unsafelyUnwrap(mightBeANumber).toString()
    : 'Nothing to log.';
    
    console.log(valueToLog);
    };

    ...we can write code like this:

    import Maybe from 'true-myth/maybe';
    
    const logValue = (mightBeANumber: Maybe<number>) => {
    const value = Maybe.match(
    {
    Just: n => n.toString(),
    Nothing: () => 'Nothing to log.',
    },
    mightBeANumber
    );
    
    console.log(value);
    };

    This is slightly longer to write, but clearer: the more complex the resulting expression, the hairer it is to understand the ternary. Thus, this is especially convenient for times when there is a complex result, e.g. when rendering part of a React component inline in JSX/TSX.

    Type parameters

    • T

    • A

    Parameters

    • matcher: Matcher<T, A>

      A lightweight object defining what to do in the case of each variant.

    • maybe: Maybe<T>

      The maybe instance to check.

    Returns A

  • Type parameters

    • T

    • A

    Parameters

    Returns function

      • Parameters

        Returns A

nothing

  • nothing<T>(_?: undefined | null): Maybe<T>
  • Create an instance of Maybe.Nothing.

    If you want to create an instance with a specific type, e.g. for use in a function which expects a Maybe<T> where the <T> is known but you have no value to give it, you can use a type parameter:

    const notString = Maybe.nothing<string>();

    Type parameters

    • T

      The type of the item contained in the Maybe.

    Parameters

    • Optional _: undefined | null

    Returns Maybe<T>

    An instance of Maybe.Nothing<T>.

of

  • of<T>(value?: T | null): Maybe<T>
  • Create a Maybe from any value.

    To specify that the result should be interpreted as a specific type, you may invoke Maybe.of with an explicit type parameter:

    const foo = Maybe.of<string>(null);

    This is usually only important in two cases:

    1. If you are intentionally constructing a Nothing from a known null or undefined value which is untyped.
    2. If you are specifying that the type is more general than the value passed (since TypeScript can define types as literals).

    Type parameters

    • T

      The type of the item contained in the Maybe.

    Parameters

    • Optional value: T | null

      The value to wrap in a Maybe. If it is undefined or null, the result will be Nothing; otherwise it will be the type of the value passed.

    Returns Maybe<T>

or

  • Provide a fallback for a given Maybe. Behaves like a logical or: if the maybe value is a Just, returns that maybe; otherwise, returns the defaultMaybe value.

    This is useful when you want to make sure that something which takes a Maybe always ends up getting a Just variant, by supplying a default value for the case that you currently have a nothing.

    import Maybe from 'true-utils/maybe';
    
    const justA = Maybe.just("a");
    const justB = Maybe.just("b");
    const aNothing: Maybe<string> = nothing();
    
    console.log(Maybe.or(justB, justA).toString());  // Just(A)
    console.log(Maybe.or(aNothing, justA).toString());  // Just(A)
    console.log(Maybe.or(justB, aNothing).toString());  // Just(B)
    console.log(Maybe.or(aNothing, aNothing).toString());  // Nothing

    Type parameters

    • T

      The type of the wrapped value.

    Parameters

    • defaultMaybe: Maybe<T>

      The Maybe to use if maybe is a Nothing.

    • maybe: Maybe<T>

      The Maybe instance to evaluate.

    Returns Maybe<T>

    maybe if it is a Just, otherwise defaultMaybe.

  • Type parameters

    • T

    Parameters

    Returns function

orElse

  • orElse<T>(elseFn: function, maybe: Maybe<T>): Maybe<T>
  • orElse<T>(elseFn: function): function
  • Like or, but using a function to construct the alternative Maybe.

    Sometimes you need to perform an operation using other data in the environment to construct the fallback value. In these situations, you can pass a function (which may be a closure) as the elseFn to generate the fallback Maybe<T>.

    Useful for transforming empty scenarios based on values in context.

    Type parameters

    • T

      The type of the wrapped value.

    Parameters

    • elseFn: function

      The function to apply if maybe is Nothing

    • maybe: Maybe<T>

      The maybe to use if it is Just.

    Returns Maybe<T>

    The maybe if it is Just, or the Maybe returned by elseFn if the maybe is Nothing.

  • Type parameters

    • T

    Parameters

    Returns function

property

  • property<T, K>(key: K, obj: T): Maybe<NonNullable<T[K]>>
  • property<T, K>(key: K): function
  • Safely extract a key from an object, returning Just if the key has a value on the object and Nothing if it does not.

    The check is type-safe: you won't even be able to compile if you try to look up a property that TypeScript knows doesn't exist on the object.

    type Person = { name?: string };
    
    const me: Person = { name: 'Chris' };
    console.log(Maybe.property('name', me)); // Just('Chris')
    
    const nobody: Person = {};
    console.log(Maybe.property('name', nobody)); // Nothing

    However, it also works correctly with dictionary types:

    type Dict<T> = { [key: string]: T };
    
    const score: Dict<number> = {
    player1: 0,
    player2: 1
    };
    
    console.log(Maybe.property('player1', score)); // Just(0)
    console.log(Maybe.property('player2', score)); // Just(1)
    console.log(Maybe.property('player3', score)); // Nothing

    The order of keys is so that it can be partially applied:

    type Person = { name?: string };
    
    const lookupName = Maybe.property('name');
    
    const me: Person = { name: 'Chris' };
    console.log(lookupName(me)); // Just('Chris')
    
    const nobody: Person = {};
    console.log(lookupName(nobody)); // Nothing

    Type parameters

    • T

    • K: keyof T

    Parameters

    • key: K

      The key to pull out of the object.

    • obj: T

      The object to look up the key from.

    Returns Maybe<NonNullable<T[K]>>

  • Type parameters

    • T

    • K: keyof T

    Parameters

    • key: K

    Returns function

      • (obj: T): Maybe<NonNullable<T[K]>>
      • Parameters

        • obj: T

        Returns Maybe<NonNullable<T[K]>>

toJSON

  • Create an Object representation of a Maybe instance.

    Useful for serialization. JSON.stringify() uses it.

    Type parameters

    • T

    Parameters

    • maybe: Maybe<T>

      The value to convert to JSON

    Returns MaybeJSON<T>

    The JSON representation of the Maybe

toOkOrElseErr

  • toOkOrElseErr<T, E>(elseFn: function, maybe: Maybe<T>): Result<T, E>
  • toOkOrElseErr<T, E>(elseFn: function): function
  • Transform the Maybe into a Result, using the wrapped value as the Ok value if Just; otherwise using elseFn to generate Err.

    Type parameters

    • T

      The wrapped value.

    • E

      The error type to in the Result.

    Parameters

    • elseFn: function

      The function which generates an error of type E.

        • (): E
        • Returns E

    • maybe: Maybe<T>

      The Maybe instance to convert.

    Returns Result<T, E>

    A Result containing the value wrapped in maybe in an Ok, or the value generated by elseFn in an Err.

  • Type parameters

    • T

    • E

    Parameters

    • elseFn: function
        • (): E
        • Returns E

    Returns function

toOkOrErr

  • toOkOrErr<T, E>(error: E, maybe: Maybe<T>): Result<T, E>
  • toOkOrErr<T, E>(error: E): function
  • Transform the Maybe into a Result, using the wrapped value as the Ok value if Just; otherwise using the supplied error value for Err.

    Type parameters

    • T

      The wrapped value.

    • E

      The error type to in the Result.

    Parameters

    • error: E

      The error value to use if the Maybe is Nothing.

    • maybe: Maybe<T>

      The Maybe instance to convert.

    Returns Result<T, E>

    A Result containing the value wrapped in maybe in an Ok, or error in an Err.

  • Type parameters

    • T

    • E

    Parameters

    • error: E

    Returns function

toString

  • toString<T>(maybe: Maybe<T>): string
  • Create a String representation of a Maybe instance.

    A Just instance will be printed as Just(<representation of the value>), where the representation of the value is simply the value's own toString representation. For example:

    call output
    toString(Maybe.of(42)) Just(42)
    toString(Maybe.of([1, 2, 3])) Just(1,2,3)
    toString(Maybe.of({ an: 'object' })) Just([object Object])
    toString(Maybe.nothing()) Nothing

    Type parameters

    • T

      The type of the wrapped value; its own .toString will be used to print the interior contents of the Just variant.

    Parameters

    • maybe: Maybe<T>

      The value to convert to a string.

    Returns string

    The string representation of the Maybe.

tuple

  • Given a tuple of Maybes, return a Maybe of the tuple values.

    Given a tuple of type [Maybe<A>, Maybe<B>], the resulting type is Maybe<[A, B]>. Works with up to a 5-tuple. (If you're doing more than a 5-tuple, what are you doing???)

    Examples

    If any of the items in the tuple are Nothing, the whole result is Nothing. Here, for example, result has the type Maybe<[string, number]> and will be Nothing:

    import Maybe from 'true-myth/maybe';
    
    type Tuple = [Maybe<string>, Maybe<number>];
    
    let invalid: Tuple = [Maybe.just('wat'), Maybe.nothing()];
    let result = Maybe.tuple(invalid);  // => Nothing

    If all of the items in the tuple are Just, the result is Just wrapping the tuple of the values of the items. Here, for example, result again has the type Maybe<[string, number]> and will be Just(['hey', 12]:

    import Maybe from 'true-myth/maybe';
    
    type Tuple = [Maybe<string>, Maybe<number>];
    
    let valid: Tuple = [Maybe.just('hey'), Maybe.just(12)];
    let result = Maybe.tuple(valid);  // => Just(['hey', 12])

    Type parameters

    • T

    Parameters

    Returns Maybe<[T]>

  • Type parameters

    • T

    • U

    Parameters

    Returns Maybe<[T, U]>

  • Type parameters

    • T

    • U

    • V

    Parameters

    Returns Maybe<[T, U, V]>

  • Type parameters

    • T

    • U

    • V

    • W

    Parameters

    Returns Maybe<[T, U, V, W]>

unsafelyUnwrap

  • unsafelyUnwrap<T>(maybe: Maybe<T>): T
  • Get the value out of the Maybe.

    Returns the content of a Just, but throws if the Maybe is Nothing. Prefer to use unwrapOr or unwrapOrElse.

    throws

    If the maybe is Nothing.

    Type parameters

    • T

      The type of the wrapped value.

    Parameters

    • maybe: Maybe<T>

      The value to unwrap

    Returns T

    The unwrapped value if the Maybe instance is Just.

unwrapOr

  • unwrapOr<T>(defaultValue: T, maybe: Maybe<T>): T
  • unwrapOr<T>(defaultValue: T): function
  • Safely get the value out of a Maybe.

    Returns the content of a Just or defaultValue if Nothing. This is the recommended way to get a value out of a Maybe most of the time.

    import Maybe from 'true-myth/maybe';
    
    const notAString = Maybe.nothing<string>();
    const isAString = Maybe.just('look ma! some characters!');
    
    console.log(Maybe.unwrapOr('<empty>', notAString));  // "<empty>"
    console.log(Maybe.unwrapOr('<empty>', isAString));  // "look ma! some characters!"

    Type parameters

    • T

      The type of the wrapped value.

    Parameters

    • defaultValue: T

      The value to return if maybe is a Nothing.

    • maybe: Maybe<T>

      The Maybe instance to unwrap if it is a Just.

    Returns T

    The content of maybe if it is a Just, otherwise defaultValue.

  • Type parameters

    • T

    Parameters

    • defaultValue: T

    Returns function

      • Parameters

        Returns T

unwrapOrElse

  • unwrapOrElse<T>(orElseFn: function, maybe: Maybe<T>): T
  • unwrapOrElse<T>(orElseFn: function): function
  • Safely get the value out of a Maybe by returning the wrapped value if it is Just, or by applying orElseFn if it is Nothing.

    This is useful when you need to generate a value (e.g. by using current values in the environment – whether preloaded or by local closure) instead of having a single default value available (as in unwrapOr).

    import Maybe from 'true-myth/maybe';
    
    // You can imagine that someOtherValue might be dynamic.
    const someOtherValue = 99;
    const handleNothing = () => someOtherValue;
    
    const aJust = Maybe.just(42);
    console.log(Maybe.unwrapOrElse(handleNothing, aJust));  // 42
    
    const aNothing = nothing<number>();
    console.log(Maybe.unwrapOrElse(handleNothing, aNothing)); // 99

    Type parameters

    • T

      The wrapped value.

    Parameters

    • orElseFn: function

      A function used to generate a valid value if maybe is a Nothing.

        • (): T
        • Returns T

    • maybe: Maybe<T>

      The Maybe instance to unwrap if it is a Just

    Returns T

    Either the content of maybe or the value returned from orElseFn.

  • Type parameters

    • T

    Parameters

    • orElseFn: function
        • (): T
        • Returns T

    Returns function

      • Parameters

        Returns T

wrapReturn

  • wrapReturn<F>(fn: F): function
  • Transform a function from a normal JS function which may return null or undefined to a function which returns a Maybe instead.

    For example, dealing with the Document#querySelector DOM API involves a lot* of things which can be null:

    const foo = document.querySelector('#foo');
    let width: number;
    if (foo !== null) {
    width = foo.getBoundingClientRect().width;
    } else {
    width = 0;
    }
    
    const getStyle = (el: HTMLElement, rule: string) => el.style[rule];
    const bar = document.querySelector('.bar');
    let color: string;
    if (bar != null) {
    let possibleColor = getStyle(bar, 'color');
    if (possibleColor !== null) {
    color = possibleColor;
    } else {
    color = 'black';
    }
    }

    (Imagine in this example that there were more than two options: the simplifying workarounds you commonly use to make this terser in JS, like the ternary operator or the short-circuiting || operator, eventually become very confusing with more complicated flows.)

    We can work around this with Maybe, always wrapping each layer in Maybe.of invocations, and this is somewhat better:

    const aWidth = Maybe.of(document.querySelector('#foo'))
    .map(el => el.getBoundingClientRect().width)
    .unwrapOr(0);
    
    const aColor = Maybe.of(document.querySelector('.bar'))
    .andThen(el => Maybe.of(getStyle(el, 'color'))
    .unwrapOr('black');

    With wrapReturn, though, you can create a transformed version of a function once* and then be able to use it freely throughout your codebase, always getting back a Maybe:

    const querySelector = Maybe.wrapReturn(document.querySelector.bind(document));
    const safelyGetStyle = Maybe.wrapReturn(getStyle);
    
    const aWidth = querySelector('#foo')
    .map(el => el.getBoundingClientRect().width)
    .unwrapOr(0);
    
    const aColor = querySelector('.bar')
    .andThen(el => safelyGetStyle(el, 'color'))
    .unwrapOr('black');

    Type parameters

    • F: function

    Parameters

    • fn: F

      The function to transform; the resulting function will have the exact same signature except for its return type.

    Returns function

      • (...args: Parameters<F>): Maybe<NonNullable<ReturnType<F>>>
      • Parameters

        • Rest ...args: Parameters<F>

        Returns Maybe<NonNullable<ReturnType<F>>>

Object literals

Const Maybe

Maybe: object

A value which may (Just<T>) or may not (Nothing) be present.

Just

Just: Just

Nothing

Nothing: Nothing

Variant

Variant: Variant

all

all: all

and

and: and

andThen

andThen: andThen

ap

ap: ap

cata

cata: match

chain

chain: andThen

equals

equals: equals

find

find: find

first

first: head

flatMap

flatMap: andThen

fromNullable

fromNullable: of

fromResult

fromResult: fromResult

get

get: get

getOr

getOr: unwrapOr

getOrElse

getOrElse: unwrapOrElse

head

head: head

ify

ify: wrapReturn = wrapReturn

isInstance

isInstance: isInstance

isJust

isJust: isJust

isNothing

isNothing: isNothing

just

just: just

last

last: last

map

map: map

mapOr

mapOr: mapOr

mapOrElse

mapOrElse: mapOrElse

match

match: match

nothing

nothing: nothing

of

of: of

or

or: or

orElse

orElse: orElse

property

property: property

toJSON

toJSON: toJSON

toOkOrElseErr

toOkOrElseErr: toOkOrElseErr

toOkOrErr

toOkOrErr: toOkOrErr

toString

toString: toString

tuple

tuple: tuple

unsafeGet

unsafeGet: unsafelyUnwrap

unsafelyGet

unsafelyGet: unsafelyUnwrap

unsafelyUnwrap

unsafelyUnwrap: unsafelyUnwrap

unwrapOr

unwrapOr: unwrapOr

unwrapOrElse

unwrapOrElse: unwrapOrElse

wrapReturn

wrapReturn: wrapReturn

Generated using TypeDoc