true-myth
- Version 8.1.0
- Published
- 572 kB
- No dependencies
- MIT license
Install
npm i true-myth
yarn add true-myth
pnpm add true-myth
Overview
Index
Variables
Interfaces
Type Aliases
Namespaces
MaybeNS
- and()
- andThen()
- AnyArray
- AnyFunction
- ap()
- equals()
- find()
- first()
- get()
- isInstance()
- isJust()
- isNothing()
- just
- Just
- JustJSON
- last()
- map()
- mapOr()
- mapOrElse()
- match()
- Matcher
- Maybe
- Maybe
- MaybeConstructor
- MaybeJSON
- NarrowingPredicate
- nothing
- Nothing
- NothingJSON
- of
- or()
- orElse()
- Predicate
- property()
- toJSON()
- toString()
- transposeArray()
- TransposedArray
- unwrapOr()
- unwrapOrElse()
- Unwrapped
- Variant
- Variant
- wrapReturn()
Variables
variable Maybe
const Maybe: MaybeConstructor;
variable Result
const Result: ResultConstructor;
The constructor for a
Result
, which represents success () or failure ().The behavior of this type is checked by TypeScript at compile time, and bears no runtime overhead other than the very small cost of the container object.
variable Unit
const Unit: Unit;
The
Unit
type exists for the cases where you want a type-safe equivalent ofundefined
ornull
. It's a concrete instance, which won't blow up on you, and you can safely use it with e.g.Result
without being concerned that you'll accidentally introducenull
orundefined
back into your application.Equivalent to
()
or "unit" in many functional or functional-influenced languages.
Interfaces
interface Unit
interface Unit extends _Unit {}
Type Aliases
Namespaces
namespace MaybeNS
module 'dist/es/maybe.d.ts' {}
variable just
const just: { <F extends (...args: any) => {}>(value: F): Maybe<F>; <T extends {}, F extends (...args: any) => T>(value: F): never; <F extends (...args: any) => null>(value: F): never; <T extends {}>(value: T): Maybe<T>;};
Create a instance which is a .
null
andundefined
are allowed by the type signature so that the function maythrow
on those rather than constructing a type likeMaybe<undefined>
.T The type of the item contained in the
Maybe
.Parameter value
The value to wrap in a
Maybe.Just
.Returns
An instance of
Maybe.Just<T>
.Throws
If you pass
null
orundefined
.
variable Maybe
const Maybe: MaybeConstructor;
variable nothing
const nothing: <T>(_?: null) => Nothing<T>;
Create a instance which is a .
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:```ts const notString = Maybe.nothing(); ```
T The type of the item contained in the
Maybe
.Returns
An instance of
Maybe.Nothing<T>
.
variable of
const of: { <F extends (...args: any) => {}>(value: F): Maybe<F>; <T extends {}, F extends (...args: any) => T>(value: F): never; <F extends (...args: any) => null>(value: F): never; <T>(value: T): Maybe<T>;};
Create a 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:```ts import * as Maybe from 'true-myth/maybe'; const foo = Maybe.of(null); ```
This is usually only important in two cases:
1. If you are intentionally constructing a
Nothing
from a knownnull
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).T The type of the item contained in the
Maybe
.Parameter value
The value to wrap in a
Maybe
. If it isundefined
ornull
, the result will beNothing
; otherwise it will be the type of the value passed.
variable Variant
const Variant: { readonly Just: 'Just'; readonly Nothing: 'Nothing' };
Discriminant for the and type instances.
You can use the discriminant via the
variant
property of instances if you need to match explicitly on it.
function and
and: { <T, U>(andMaybe: Maybe<U>, maybe: Maybe<T>): Maybe<U>; <T, U>(andMaybe: Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;};
You can think of this like a short-circuiting logical "and" operation on a type. If
maybe
is , then the result is theandMaybe
. Ifmaybe
is , the result isNothing
.This is useful when you have another
Maybe
value you want to provide if and only if* you have aJust
– that is, when you need to make sure that if youNothing
, whatever else you're handing aMaybe
to *also* gets aNothing
.Notice that, unlike in [
map
](#map) or its variants, the originalmaybe
is not involved in constructing the newMaybe
.#### Examples
```ts import Maybe from 'true-myth/maybe';
const justA = Maybe.just('A'); const justB = Maybe.just('B'); const nothing: Maybe = 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 ```
T The type of the initial wrapped value. U The type of the wrapped value of the returned
Maybe
.Parameter andMaybe
The
Maybe
instance to return ifmaybe
isJust
Parameter maybe
The
Maybe
instance to check.Nothing
if the originalmaybe
isNothing
, orandMaybe
if the originalmaybe
isJust
.
function andThen
andThen: { <T, U>(thenFn: (t: T) => Maybe<U>, maybe: Maybe<T>): Maybe<U>; <T, U>(thenFn: (t: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;};
Apply a function to the wrapped value if and return a new
Just
containing the resulting value; or return ifNothing
.This differs from in that
thenFn
returns anotherMaybe
. You can useandThen
to combine two functions which *both* create aMaybe
from an unwrapped type.You may find the
.then
method on an ES6Promise
helpful for comparison: if you have aPromise
, you can pass itsthen
method a callback which returns anotherPromise
, and the result will not be a *nested* promise, but a singlePromise
. The difference is thatPromise#then
unwraps *all* layers to only ever return a singlePromise
value, whereasMaybe.andThen
will not unwrap nestedMaybe
s.This is sometimes also known as
bind
, but *not* aliased as such because [bind
already means something in JavaScript][bind].[bind]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
#### Example
(This is a somewhat contrived example, but it serves to show the way the function behaves.)
```ts import Maybe, { andThen, toString } from 'true-myth/maybe';
// string -> Maybe const toMaybeLength = (s: string) => Maybe.of(s.length);
// Maybe const aMaybeString = Maybe.of('Hello, there!');
// Maybe const resultingLength = andThen(toMaybeLength, aMaybeString); console.log(toString(resultingLength)); // 13 ```
Note that the result is not
Just(Just(13))
, butJust(13)
!T The type of the wrapped value. U The type of the wrapped value in the resulting
Maybe
.Parameter thenFn
The function to apply to the wrapped
T
ifmaybe
isJust
.Parameter maybe
The
Maybe
to evaluate and possibly apply a function to the contents of.Returns
The result of the
thenFn
(a newMaybe
) ifmaybe
is aJust
, otherwiseNothing
ifmaybe
is aNothing
.
function ap
ap: { <T, U extends {}>(maybeFn: Maybe<(t: T) => U>, maybe: Maybe<T>): Maybe<U>; <T, U extends {}>(maybeFn: Maybe<(t: T) => U>): (maybe: Maybe<T>) => Maybe<U>;};
Allows you to *apply* (thus
ap
) a value to a function without having to take either out of the context of their s. This does mean that the transforming function is itself within aMaybe
, which can be hard to grok at first but lets you do some very elegant things. For example,ap
allows you to this:```ts 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
ap
, you'd need to do something like a nestedmatch
:```ts 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. Withap
, that's as simple as this:```ts import Maybe from 'true-myth/maybe'; import { is as immutableIs, Set } from 'immutable';
const is = (first: unknown) => (second: unknown) => immutableIs(first, second);
const x = Maybe.of(Set.of(1, 2, 3)); const y = Maybe.of(Set.of(2, 3, 4));
Maybe.of(is).ap(x).ap(y); // Just(false) ```
Without
ap
, we're back to that gnarly nestedmatch
:```ts import Maybe, { just, nothing } from 'true-myth/maybe'; import { is, Set } from 'immutable';
const x = Maybe.of(Set.of(1, 2, 3)); const y = Maybe.of(Set.of(2, 3, 4));
x.match({ Just: iX => y.match({ Just: iY => Maybe.just(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.(Unfortunately, these do not currently work with lodash or Ramda's
curry
helper functions. A future update to the type definitions may make that work, but the intermediate types produced by those helpers and the more general function types expected by this function do not currently align.)2. 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 thisadd3
function, which has the "arity" (function argument count) of 3 (a
andb
), you'll need to callap
twice: once fora
, and once forb
. To see why, let's look at what the result in each phase is:```ts const add3 = (a: number) => (b: number) => (c: number) => a + b + c;
const maybeAdd = just(add3); // Just((a: number) => (b: number) => (c: number) => a + b + c) const maybeAdd1 = maybeAdd.ap(just(1)); // Just((b: number) => (c: number) => 1 + b + c) const maybeAdd1And2 = maybeAdd1.ap(just(2)) // Just((c: number) => 1 + 2 + c) const final = maybeAdd1.ap(just(3)); // Just(4) ```
So for
toString
, which just takes a single argument, you would only need to callap
once.```ts const toStr = (v: { toString(): string }) => v.toString(); just(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 inap
and then wrap the values to apply to the function to inMaybe
themselves.__Aside:__
ap
is not namedapply
because of the overlap with JavaScript's existing [apply
] function – and although strictly speaking, there isn't any direct overlap (Maybe.apply
andFunction.prototype.apply
don't intersect at all) it's useful to have a different name to avoid implying that they're the same.[
apply
]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/applyParameter maybeFn
maybe a function from T to U
Parameter maybe
maybe a T to apply to
fn
function equals
equals: { <T>(mb: Maybe<T>, ma: Maybe<T>): boolean; <T>(mb: Maybe<T>): (ma: Maybe<T>) => boolean;};
Allows quick triple-equal equality check between the values inside two instances without having to unwrap them first.
```ts 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 ```
Parameter mb
A
maybe
to compare to.Parameter ma
A
maybe
instance to check.
function find
find: { <T, U extends T>( predicate: NarrowingPredicate<T, U>, array: AnyArray<T> ): Maybe<U>; <T, U extends T>(predicate: NarrowingPredicate<T, U>): ( array: AnyArray<T> ) => Maybe<U>; <T>(predicate: Predicate<T>, array: AnyArray<T>): Maybe<T>; <T>(predicate: Predicate<T>): (array: AnyArray<T>) => Maybe<T>;};
Safely search for an element in an array.
This function behaves like
Array.prototype.find
, but returnsMaybe<T>
instead ofT | undefined
.## Examples
The basic form is:
```ts 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 typeArray<{ count: number, name: string }>
, and we wanted to get the first of these wherecount
was at least 100. We could write this:```ts import Maybe from 'true-myth/maybe';
type Item = { count: number; name: string }; type Response = Array;
// 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}!
); } }); ```Parameter predicate
A function to execute on each value in the array, returning
true
when the item in the array matches the condition. The signature forpredicate
is identical to the signature for the first argument toArray.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 inJust
. Otherwise,Maybe.find
returnsNothing
.Parameter array
The array to search using the predicate.
function first
first: <T>(array: AnyArray<T | null | undefined>) => Maybe<T>;
Safely get the first item from a list, returning the first item if the array has at least one item in it, or if it is empty.
## Examples
```ts let empty = []; Maybe.head(empty); // => Nothing
let full = [1, 2, 3]; Maybe.head(full); // => Just(1) ```
Parameter array
The array to get the first item from.
function get
get: { <T, K extends keyof T>(key: K, maybeObj: Maybe<T>): Maybe<NonNullable<T[K]>>; <T, K extends keyof T>(key: K): (maybeObj: Maybe<T>) => Maybe<NonNullable<T[K]>>;};
Safely extract a key from a of an object, returning if the key has a value on the object and if it does not. (Like but operating on a
Maybe<T>
rather than directly on aT
.)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.
```ts import { get, just, nothing } from 'true-myth/maybe';
type Person = { name?: string };
const me: Maybe = just({ name: 'Chris' }); console.log(get('name', me)); // Just('Chris')
const nobody = nothing(); console.log(get('name', nobody)); // Nothing ```
However, it also works correctly with dictionary types:
```ts import { get, just } from 'true-myth/maybe';
type Dict = { [key: string]: T };
const score: Maybe<Dict> = just({ player1: 0, player2: 1 });
console.log(get('player1', score)); // Just(0) console.log(get('player2', score)); // Just(1) console.log(get('player3', score)); // Nothing ```
The order of keys is so that it can be partially applied:
```ts import { get, just } from 'true-myth/maybe';
type Person = { name?: string };
const lookupName = get('name');
const me: Person = { name: 'Chris' }; console.log(lookupName(me)); // Just('Chris')
const nobody: Person = {}; console.log(lookupName(nobody)); // Nothing ```
Parameter key
The key to pull out of the object.
Parameter maybeObj
The object to look up the key from.
function isInstance
isInstance: <T>(item: unknown) => item is Maybe<T>;
Determine whether an item is an instance of .
Parameter item
The item to check.
function isJust
isJust: <T>(maybe: Maybe<T>) => maybe is Just<T>;
Is the a ?
T The type of the item contained in the
Maybe
.Parameter maybe
The
Maybe
to check.Returns
A type guarded
Just
.
function isNothing
isNothing: <T>(maybe: Maybe<T>) => maybe is Nothing<T>;
Is the a ?
T The type of the item contained in the
Maybe
.Parameter maybe
The
Maybe
to check.Returns
A type guarded
Nothing
.
function last
last: <T>(array: AnyArray<T | null | undefined>) => Maybe<T>;
Safely get the last item from a list, returning the last item if the array has at least one item in it, or if it is empty.
## Examples
```ts let empty = []; Maybe.last(empty); // => Nothing
let full = [1, 2, 3]; Maybe.last(full); // => Just(3) ```
Parameter array
The array to get the first item from.
function map
map: { <T, U extends {}>(mapFn: (t: T) => U): (maybe: Maybe<T>) => Maybe<U>; <T, U extends {}>(mapFn: (t: T) => U, maybe: Maybe<T>): Maybe<U>;};
Map over a instance: apply the function to the wrapped value if the instance is , and return if the instance is
Nothing
.map
works a lot likeArray.prototype.map
:Maybe
andArray
are both containers* for other things. If you have no items in an array of numbers namedfoo
and callfoo.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 callfoo.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
map
. If the container is *empty* – theNothing
variant – you just get back an empty container. If the container has something in it – theJust
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
```ts 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(); const notAStringLength = map(length, notAString); console.log(notAStringLength.toString()); // "Nothing" ```
T The type of the wrapped value. U The type of the wrapped value of the returned
Maybe
.Parameter mapFn
The function to apply the value to if
Maybe
isJust
.Returns
A function accepting a
Maybe<T>
, which will produceMaybe<U>
after applyingmapFn
.Map over a instance: apply the function to the wrapped value if the instance is , and return if the instance is
Nothing
.map
works a lot likeArray.prototype.map
:Maybe
andArray
are both containers* for other things. If you have no items in an array of numbers namedfoo
and callfoo.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 callfoo.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
map
. If the container is *empty* – theNothing
variant – you just get back an empty container. If the container has something in it – theJust
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
```ts 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(); const notAStringLength = map(length, notAString); console.log(notAStringLength.toString()); // "Nothing" ```
T The type of the wrapped value. U The type of the wrapped value of the returned
Maybe
.Parameter mapFn
The function to apply the value to if
Maybe
isJust
.Parameter maybe
The
Maybe
instance to map over.Returns
A new
Maybe
with the result of applyingmapFn
to the value in aJust
, orNothing
ifmaybe
isNothing
.
function mapOr
mapOr: { <T, U>(orU: U, mapFn: (t: T) => U, maybe: Maybe<T>): U; <T, U>(orU: U, mapFn: (t: T) => U): (maybe: Maybe<T>) => U; <T, U>(orU: U): (mapFn: (t: T) => U) => (maybe: Maybe<T>) => U;};
Map over a instance and get out the value if
maybe
is a , or return a default value ifmaybe
is a .#### Examples
```ts 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(); const notAStringLength = mapOr(0, length, notAString) console.log(notAStringLength); // 0 ```
T The type of the wrapped value. U The type of the wrapped value of the returned
Maybe
.Parameter orU
The default value to use if
maybe
isNothing
Parameter mapFn
The function to apply the value to if
Maybe
isJust
Parameter maybe
The
Maybe
instance to map over.
function mapOrElse
mapOrElse: { <T, U>(orElseFn: () => U, mapFn: (t: T) => U, maybe: Maybe<T>): U; <T, U>(orElseFn: () => U, mapFn: (t: T) => U): (maybe: Maybe<T>) => U; <T, U>(orElseFn: () => U): (mapFn: (t: T) => U) => (maybe: Maybe<T>) => U;};
Map over a instance and get out the value if
maybe
is a , or use a function to construct a default value ifmaybe
is .#### Examples
```ts 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(); const notAStringLength = mapOrElse(getDefault, length, notAString) console.log(notAStringLength); // 0 ```
T The type of the wrapped value. U The type of the wrapped value of the returned
Maybe
.Parameter orElseFn
The function to apply if
maybe
isNothing
.Parameter mapFn
The function to apply to the wrapped value if
maybe
isJust
Parameter maybe
The
Maybe
instance to map over.
function match
match: { <T, A>(matcher: Matcher<T, A>, maybe: Maybe<T>): A; <T, A>(matcher: Matcher<T, A>): (m: Maybe<T>) => A;};
Performs the same basic functionality as , but instead of simply unwrapping the value if it is and applying a value to generate the same default type if it is , lets you supply functions which may transform the wrapped type if it is
Just
or get a default value forNothing
.This is kind of like a poor man's version of pattern matching, which JavaScript currently lacks.
Instead of code like this:
```ts import Maybe from 'true-myth/maybe';
const logValue = (mightBeANumber: Maybe) => { const valueToLog = Maybe.mightBeANumber.isJust ? mightBeANumber.value.toString() : 'Nothing to log.';
console.log(valueToLog); }; ```
...we can write code like this:
```ts import { match } from 'true-myth/maybe';
const logValue = (mightBeANumber: Maybe) => { const value = 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.
Parameter matcher
A lightweight object defining what to do in the case of each variant.
Parameter maybe
The
maybe
instance to check.
function or
or: { <T>(defaultMaybe: Maybe<T>, maybe: Maybe<T>): Maybe<T>; <T>(defaultMaybe: Maybe<T>): (maybe: Maybe<T>) => Maybe<T>;};
Provide a fallback for a given . Behaves like a logical
or
: if themaybe
value is a , returns thatmaybe
; otherwise, returns thedefaultMaybe
value.This is useful when you want to make sure that something which takes a
Maybe
always ends up getting aJust
variant, by supplying a default value for the case that you currently have a nothing.```ts import Maybe from 'true-utils/maybe';
const justA = Maybe.just("a"); const justB = Maybe.just("b"); const aNothing: Maybe = 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 ```
T The type of the wrapped value.
Parameter defaultMaybe
The
Maybe
to use ifmaybe
is aNothing
.Parameter maybe
The
Maybe
instance to evaluate.Returns
maybe
if it is aJust
, otherwisedefaultMaybe
.
function orElse
orElse: { <T>(elseFn: () => Maybe<T>, maybe: Maybe<T>): Maybe<T>; <T>(elseFn: () => Maybe<T>): (maybe: Maybe<T>) => Maybe<T>;};
Like , but using a function to construct the alternative .
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 fallbackMaybe<T>
.Useful for transforming empty scenarios based on values in context.
T The type of the wrapped value.
Parameter elseFn
The function to apply if
maybe
isNothing
Parameter maybe
The
maybe
to use if it isJust
.Returns
The
maybe
if it isJust
, or theMaybe
returned byelseFn
if themaybe
isNothing
.
function property
property: { <T, K extends keyof T>(key: K, obj: T): Maybe<NonNullable<T[K]>>; <T, K extends keyof T>(key: K): (obj: T) => Maybe<NonNullable<T[K]>>;};
Safely extract a key from an object, returning if the key has a value on the object and 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.
```ts 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:
```ts type Dict = { [key: string]: T };
const score: Dict = { 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:
```ts 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 ```
Parameter key
The key to pull out of the object.
Parameter obj
The object to look up the key from.
function toJSON
toJSON: <T>(maybe: Maybe<T>) => MaybeJSON<unknown>;
Create an
Object
representation of a instance.Useful for serialization.
JSON.stringify()
uses it.Parameter maybe
The value to convert to JSON
Returns
The JSON representation of the
Maybe
function toString
toString: <T>(maybe: Maybe<T>) => string;
Create a
String
representation of a instance.A instance will be
Just(<representation of the value>)
, where the representation of the value is simply the value's owntoString
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
|T The type of the wrapped value; its own
.toString
will be used to print the interior contents of theJust
variant.Parameter maybe
The value to convert to a string.
Returns
The string representation of the
Maybe
.
function transposeArray
transposeArray: <T extends Maybe<unknown>[]>(maybes: T) => TransposedArray<T>;
Given an array or tuple of s, return a
Maybe
of the array or tuple values.- Given an array of type
Array<Maybe<A> | Maybe<B>>
, the resulting type isMaybe<Array<A | B>>
. - Given a tuple of type[Maybe<A>, Maybe<B>]
, the resulting type isMaybe<[A, B]>
.If any of the items in the array or tuple are , the whole result is
Nothing
. If all items in the array or tuple are , the whole result isJust
.## Examples
Given an array with a mix of
Maybe
types in it, bothallJust
andmixed
here will have the typeMaybe<Array<string | number>>
, but will beJust
andNothing
respectively.```ts import Maybe, { transposeArray } from 'true-myth/maybe';
let valid = [Maybe.just(2), Maybe.just('three')]; let allJust = transposeArray(valid); // => Just([2, 'three']);
let invalid = [Maybe.just(2), Maybe.nothing()]; let mixed = transposeArray(invalid); // => Nothing ```
When working with a tuple type, the structure of the tuple is preserved. Here, for example,
result
has the typeMaybe<[string, number]>
and will beNothing
:```ts import Maybe, { transposeArray } from 'true-myth/maybe';
type Tuple = [Maybe, Maybe];
let invalid: Tuple = [Maybe.just('wat'), Maybe.nothing()]; let result = transposeArray(invalid); // => Nothing ```
If all of the items in the tuple are
Just
, the result isJust
wrapping the tuple of the values of the items. Here, for example,result
again has the typeMaybe<[string, number]>
and will beJust(['hey', 12]
:```ts import Maybe, { transposeArray } from 'true-myth/maybe';
type Tuple = [Maybe, Maybe];
let valid: Tuple = [Maybe.just('hey'), Maybe.just(12)]; let result = transposeArray(valid); // => Just(['hey', 12]) ```
__Note:__ this does not work with
ReadonlyArray
. If you have aReadonlyArray
you wish to operate on, you must cast it toArray
insetad. This cast is always safe here, becauseArray
is a *wider* type thanReadonlyArray
.Parameter maybes
The
Maybe
s to resolve to a singleMaybe
.
function unwrapOr
unwrapOr: { <T, U>(defaultValue: U, maybe: Maybe<T>): T | U; <T, U>(defaultValue: U): (maybe: Maybe<T>) => T | U;};
Safely get the value out of a .
Returns the content of a or
defaultValue
if . This is the recommended way to get a value out of aMaybe
most of the time.```ts import Maybe from 'true-myth/maybe';
const notAString = Maybe.nothing(); const isAString = Maybe.just('look ma! some characters!');
console.log(Maybe.unwrapOr('', notAString)); // "" console.log(Maybe.unwrapOr('', isAString)); // "look ma! some characters!" ```
T The type of the wrapped value.
Parameter defaultValue
The value to return if
maybe
is aNothing
.Parameter maybe
The
Maybe
instance to unwrap if it is aJust
.Returns
The content of
maybe
if it is aJust
, otherwisedefaultValue
.
function unwrapOrElse
unwrapOrElse: { <T, U>(orElseFn: () => U, maybe: Maybe<T>): T | U; <T, U>(orElseFn: () => U): (maybe: Maybe<T>) => T | U;};
Safely get the value out of a by returning the wrapped value if it is , or by applying
orElseFn
if it is .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 ).
```ts 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(); console.log(Maybe.unwrapOrElse(handleNothing, aNothing)); // 99 ```
T The wrapped value.
Parameter orElseFn
A function used to generate a valid value if
maybe
is aNothing
.Parameter maybe
The
Maybe
instance to unwrap if it is aJust
Returns
Either the content of
maybe
or the value returned fromorElseFn
.
function wrapReturn
wrapReturn: < F extends AnyFunction, P extends Parameters<F>, R extends NonNullable<ReturnType<F>>>( fn: F) => (...args: P) => Maybe<R>;
Transform a function from a normal JS function which may return
null
orundefined
to a function which returns a instead.For example, dealing with the
Document#querySelector
DOM API involves a lot* of things which can benull
:```ts 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
||
or??
operators, eventually become very confusing with more complicated flows.)We can work around this with
Maybe
, always wrapping each layer in invocations, and this is *somewhat* better:```ts import Maybe from 'true-myth/maybe';
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 aMaybe
:```ts import { wrapReturn } from 'true-myth/maybe';
const querySelector = wrapReturn(document.querySelector.bind(document)); const safelyGetStyle = wrapReturn(getStyle);
const aWidth = querySelector('#foo') .map(el => el.getBoundingClientRect().width) .unwrapOr(0);
const aColor = querySelector('.bar') .andThen(el => safelyGetStyle(el, 'color')) .unwrapOr('black'); ```
Parameter fn
The function to transform; the resulting function will have the exact same signature except for its return type.
interface Just
interface Just<T> extends MaybeImpl<T> {}
A
Just
instance is the *present* variant instance of the type, representing the presence of a value which may be absent. For a full discussion, see the module docs.T The type wrapped in this
Just
variant ofMaybe
.
interface MaybeConstructor
interface MaybeConstructor {}
The public interface for the class *as a value*: a constructor and the associated static properties.
property just
just: typeof MaybeImpl.just;
property nothing
nothing: typeof MaybeImpl.nothing;
property of
of: typeof MaybeImpl.of;
construct signature
new <T>(value?: T | null | undefined): Maybe<T>;
interface Nothing
interface Nothing<T> extends Omit<MaybeImpl<T>, 'value'> {}
A
Nothing
instance is the *absent* variant instance of the type, representing the presence of a value which may be absent. For a full discussion, see the module docs.T The type which would be wrapped in a variant of the .
interface NothingJSON
interface NothingJSON {}
property variant
variant: 'Nothing';
type AnyArray
type AnyArray<T> = Array<T> | ReadonlyArray<T>;
An array or a readonly array.
type AnyFunction
type AnyFunction = (...args: never[]) => unknown;
This is the standard *correct* definition for a function which is a proper subtype of all other functions: parameters of a function subtype must be wider* than those of the base type, and return types must be *narrower*. Everything is wider than
never[]
and narrower thanunknown
, so any function is assignable to places this is used.
type Matcher
type Matcher<T, A> = { Just: (value: T) => A; Nothing: () => A;};
A lightweight object defining how to handle each variant of a .
type Maybe
type Maybe<T> = Just<T> | Nothing<T>;
A value which may () or may not () be present.
type MaybeJSON
type MaybeJSON<T> = JustJSON<T> | NothingJSON;
type NarrowingPredicate
type NarrowingPredicate<T, U extends T> = ( element: T, index: number, array: AnyArray<T>) => element is U;
type Predicate
type Predicate<T> = (element: T, index: number, array: AnyArray<T>) => boolean;
type TransposedArray
type TransposedArray<T extends Array<Maybe<unknown>>> = Maybe<{ [K in keyof T]: Unwrapped<T[K]>;}>;
type Unwrapped
type Unwrapped<T> = T extends Maybe<infer U> ? U : T;
type Variant
type Variant = keyof typeof Variant;
namespace ResultNS
module 'dist/es/result.d.ts' {}
variable err
const err: { <T = never, E = never>(): Result<T, Unit>; <T = never, E = never>(error: E): Result<T, E>;};
Create an instance of .
If you need to create an instance with a specific type (as you do whenever you are not constructing immediately for a function return or as an argument to a function), you can use a type parameter:
```ts const notString = Result.err<number, string>('something went wrong'); ```
Note: passing nothing, or passing
null
orundefined
explicitly, will produce aResult<T, Unit>
, rather than producing the nonsensical and in practice quite annoyingResult<null, string>
etc. See for more.```ts const normalResult = Result.err<number, string>('oh no'); const explicitUnit = Result.err<number, Unit>(Unit); const implicitUnit = Result.err<number, Unit>(); ```
In the context of an immediate function return, or an arrow function with a single expression value, you do not have to specify the types, so this can be quite convenient.
```ts type SomeData = { //... };
const isValid = (data: SomeData): boolean => { // true or false... }
const arrowValidate = (data: SomeData): Result<number, Unit> => isValid(data) ? Result.ok(42) : Result.err();
function fnValidate(data: someData): Result<number, Unit> { return isValid(data) ? Result.ok(42) : Result.err(); } ```
T The type of the item contained in the
Result
.Parameter E
The error value to wrap in a
Result.Err
.
variable ok
const ok: { <T extends {}, E = never>(): Result<Unit, E>; <T, E = never>(value: T): Result<T, E>;};
Create an instance of .
If you need to create an instance with a specific type (as you do whenever you are not constructing immediately for a function return or as an argument to a function), you can use a type parameter:
```ts const yayNumber = Result.ok<number, string>(12); ```
Note: passing nothing, or passing
null
orundefined
explicitly, will produce aResult<Unit, E>
, rather than producing the nonsensical and in practice quite annoyingResult<null, string>
etc. See for more.```ts const normalResult = Result.ok<number, string>(42); const explicitUnit = Result.ok<Unit, string>(Unit); const implicitUnit = Result.ok<Unit, string>(); ```
In the context of an immediate function return, or an arrow function with a single expression value, you do not have to specify the types, so this can be quite convenient.
```ts type SomeData = { //... };
const isValid = (data: SomeData): boolean => { // true or false... }
const arrowValidate = (data: SomeData): Result<Unit, string> => isValid(data) ? Result.ok() : Result.err('something was wrong!');
function fnValidate(data: someData): Result<Unit, string> { return isValid(data) ? Result.ok() : Result.err('something was wrong'); } ```
T The type of the item contained in the
Result
.Parameter value
The value to wrap in a
Result.Ok
.
variable Result
const Result: ResultConstructor;
The constructor for a
Result
, which represents success () or failure ().The behavior of this type is checked by TypeScript at compile time, and bears no runtime overhead other than the very small cost of the container object.
variable Variant
const Variant: { readonly Ok: 'Ok'; readonly Err: 'Err' };
Discriminant for and variants of the type.
You can use the discriminant via the
variant
property ofResult
instances if you need to match explicitly on it.
function and
and: { <T, U, E>(andResult: Result<U, E>, result: Result<T, E>): Result<U, E>; <T, U, E>(andResult: Result<U, E>): (result: Result<T, E>) => Result<U, E>;};
You can think of this like a short-circuiting logical "and" operation on a type. If
result
is , then the result is theandResult
. Ifresult
is , the result is theErr
.This is useful when you have another
Result
value you want to provide if and only if* you have anOk
– that is, when you need to make sure that if youErr
, whatever else you're handing aResult
to *also* gets thatErr
.Notice that, unlike in [
map
](#map) or its variants, the originalresult
is not involved in constructing the newResult
.#### Examples
```ts import { and, ok, err, toString } from 'true-myth/result';
const okA = ok('A'); const okB = ok('B'); const anErr = err({ so: 'bad' });
console.log(toString(and(okB, okA))); // Ok(B) console.log(toString(and(okB, anErr))); // Err([object Object]) console.log(toString(and(anErr, okA))); // Err([object Object]) console.log(toString(and(anErr, anErr))); // Err([object Object]) ```
T The type of the value wrapped in the
Ok
of theResult
. U The type of the value wrapped in theOk
of theandResult
, i.e. the success type of theResult
present if the checkedResult
isOk
. E The type of the value wrapped in theErr
of theResult
.Parameter andResult
The
Result
instance to return ifresult
isErr
.Parameter result
The
Result
instance to check.
function andThen
andThen: { <T, U, E>(thenFn: (t: T) => Result<U, E>, result: Result<T, E>): Result<U, E>; <T, U, E>(thenFn: (t: T) => Result<U, E>): ( result: Result<T, E> ) => Result<U, E>;};
Apply a function to the wrapped value if and return a new
Ok
containing the resulting value; or if it is return it unmodified.This differs from
map
in thatthenFn
returns another . You can useandThen
to combine two functions which *both* create aResult
from an unwrapped type.You may find the
.then
method on an ES6Promise
helpful for comparison: if you have aPromise
, you can pass itsthen
method a callback which returns anotherPromise
, and the result will not be a *nested* promise, but a singlePromise
. The difference is thatPromise#then
unwraps *all* layers to only ever return a singlePromise
value, whereasResult.andThen
will not unwrap nestedResult
s.This is is sometimes also known as
bind
, but *not* aliased as such because [bind
already means something in JavaScript][bind].[bind]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
#### Examples
```ts import { ok, err, andThen, toString } from 'true-myth/result';
const toLengthAsResult = (s: string) => ok(s.length);
const anOk = ok('just a string'); const lengthAsResult = andThen(toLengthAsResult, anOk); console.log(toString(lengthAsResult)); // Ok(13)
const anErr = err(['srsly', 'whatever']); const notLengthAsResult = andThen(toLengthAsResult, anErr); console.log(toString(notLengthAsResult)); // Err(srsly,whatever) ```
T The type of the value wrapped in the
Ok
of theResult
. U The type of the value wrapped in theOk
of theResult
returned by thethenFn
. E The type of the value wrapped in theErr
of theResult
.Parameter thenFn
The function to apply to the wrapped
T
ifmaybe
isJust
.Parameter result
The
Maybe
to evaluate and possibly apply a function to.
function ap
ap: { <A, B, E>(resultFn: Result<(a: A) => B, E>, result: Result<A, E>): Result<B, E>; <A, B, E>(resultFn: Result<(a: A) => B, E>): ( result: Result<A, E> ) => Result<B, E>;};
Allows you to *apply* (thus
ap
) a value to a function without having to take either out of the context of their s. This does mean that the transforming function is itself within aResult
, which can be hard to grok at first but lets you do some very elegant things. For example,ap
allows you to do this (using the method form, since nestingap
calls is awkward):```ts import { ap, ok, err } from 'true-myth/result';
const one = ok<number, string>(1); const five = ok<number, string>(5); const whoops = err<number, string>('oh no');
const add = (a: number) => (b: number) => a + b; const resultAdd = ok<typeof add, string>(add);
resultAdd.ap(one).ap(five); // Ok(6) resultAdd.ap(one).ap(whoops); // Err('oh no') resultAdd.ap(whoops).ap(five) // Err('oh no') ```
Without
ap
, you'd need to do something like a nestedmatch
:```ts import { ok, err } from 'true-myth/result';
const one = ok<number, string>(1); const five = ok<number, string>(5); const whoops = err<number, string>('oh no');
one.match({ Ok: n => five.match({ Ok: o => ok<number, string>(n + o), Err: e => err<number, string>(e), }), Err: e => err<number, string>(e), }); // Ok(6)
one.match({ Ok: n => whoops.match({ Ok: o => ok<number, string>(n + o), Err: e => err<number, string>(e), }), Err: e => err<number, string>(e), }); // Err('oh no')
whoops.match({ Ok: n => five.match({ Ok: o => ok(n + o), Err: e => err(e), }), Err: e => err(e), }); // Err('oh no') ```
And this kind of thing comes up quite often once you're using
Result
to handle errors throughout your application.For another example, imagine you need to compare the equality of two ImmutableJS data structures, where a
===
comparison won't work. Withap
, that's as simple as this:```ts import { ok } from 'true-myth/result'; import { is as immutableIs, Set } from 'immutable';
const is = (first: unknown) => (second: unknown) => immutableIs(first, second);
const x = ok(Set.of(1, 2, 3)); const y = ok(Set.of(2, 3, 4));
ok(is).ap(x).ap(y); // Ok(false) ```
Without
ap
, we're back to that gnarly nestedmatch
:```ts import Result, { ok, err } from 'true-myth/result'; import { is, Set } from 'immutable';
const x = ok(Set.of(1, 2, 3)); const y = ok(Set.of(2, 3, 4));
x.match({ Ok: iX => y.match({ Ok: iY => Result.of(is(iX, iY)), Err: (e) => ok(false), }) Err: (e) => ok(false), }); // Ok(false) ```
In summary: anywhere you have two
Result
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.(Unfortunately, these do not currently work with lodash or Ramda's
curry
helper functions. A future update to the type definitions may make that work, but the intermediate types produced by those helpers and the more general function types expected by this function do not currently align.)2. 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 thisadd3
function, which has the "arity" (function argument count) of 3 (a
andb
), you'll need to callap
twice: once fora
, and once forb
. To see why, let's look at what the result in each phase is:```ts const add3 = (a: number) => (b: number) => (c: number) => a + b + c;
const resultAdd = ok(add); // Ok((a: number) => (b: number) => (c: number) => a + b + c) const resultAdd1 = resultAdd.ap(ok(1)); // Ok((b: number) => (c: number) => 1 + b + c) const resultAdd1And2 = resultAdd1.ap(ok(2)) // Ok((c: number) => 1 + 2 + c) const final = maybeAdd1.ap(ok(3)); // Ok(4) ```
So for
toString
, which just takes a single argument, you would only need to callap
once.```ts const toStr = (v: { toString(): string }) => v.toString(); ok(toStr).ap(12); // Ok("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
Result
scenario. In that case, you can wrap the possibly-present inap
and then wrap the values to apply to the function to inResult
themselves.Because
Result
often requires you to type out the full type parameterization on a regular basis, it's convenient to use TypeScript'stypeof
operator to write out the type of a curried function. For example, if you had a function that simply merged three strings, you might write it like this:```ts import Result from 'true-myth/result'; import { curry } from 'lodash';
const merge3Strs = (a: string, b: string, c: string) => string; const curriedMerge = curry(merge3Strs);
const fn = Result.ok<typeof curriedMerge, string>(curriedMerge); ```
The alternative is writing out the full signature long-form:
```ts const fn = Result.ok<(a: string) => (b: string) => (c: string) => string, string>(curriedMerge); ```
*Aside:**
ap
is not namedapply
because of the overlap with JavaScript's existing [apply
] function – and although strictly speaking, there isn't any direct overlap (Result.apply
andFunction.prototype.apply
don't intersect at all) it's useful to have a different name to avoid implying that they're the same.[
apply
]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/applyParameter resultFn
result of a function from T to U
Parameter result
result of a T to apply to
fn
function equals
equals: { <T, E>(resultB: Result<T, E>, resultA: Result<T, E>): boolean; <T, E>(resultB: Result<T, E>): (resultA: Result<T, E>) => boolean;};
Allows quick triple-equal equality check between the values inside two s without having to unwrap them first.
```ts const a = Result.of(3) const b = Result.of(3) const c = Result.of(null) const d = Result.nothing()
Result.equals(a, b) // true Result.equals(a, c) // false Result.equals(c, d) // true ```
Parameter resultB
A
maybe
to compare to.Parameter resultA
A
maybe
instance to check.
function isErr
isErr: <T, E>(result: Result<T, E>) => result is Err<T, E>;
Is the an ?
T The type of the item contained in the
Result
.Parameter result
The
Result
to check.Returns
A type guarded
Err
.
function isInstance
isInstance: <T, E>(item: unknown) => item is Result<T, E>;
Determine whether an item is an instance of .
Parameter item
The item to check.
function isOk
isOk: <T, E>(result: Result<T, E>) => result is Ok<T, E>;
Is the an ?
T The type of the item contained in the
Result
.Parameter result
The
Result
to check.Returns
A type guarded
Ok
.
function map
map: { <T, U, E>(mapFn: (t: T) => U, result: Result<T, E>): Result<U, E>; <T, U, E>(mapFn: (t: T) => U): (result: Result<T, E>) => Result<U, E>;};
Map over a instance: apply the function to the wrapped value if the instance is , and return the wrapped error value wrapped as a new of the correct type (
Result<U, E>
) if the instance isErr
.map
works a lot likeArray.prototype.map
, but with one important difference. BothResult
andArray
are containers for other kinds of items, but whereArray.prototype.map
has 0 to _n_ items, aResult
always has exactly one item, which is *either* a success or an error instance.Where
Array.prototype.map
will apply the mapping function to every item in the array (if there are any),Result.map
will only apply the mapping function to the (single) element if anOk
instance, if there is one.If you have no items in an array of numbers named
foo
and call `foo.map(x => x + 1)`, you'll still some have an array with nothing in it. But if you have any items in the array ([2, 3]
), and you callfoo.map(x => x + 1)
on it, you'll get a new array with each of those items inside the array "container" transformed ([3, 4]
).With this
map
, theErr
variant is treated *by themap
function* kind of the same way as the empty array case: it's just ignored, and you get back a newResult
that is still just the sameErr
instance. But if you have anOk
variant, the map function is applied to it, and you get back a newResult
with the value transformed, and still wrapped in anOk
.#### Examples
```ts import { ok, err, map, toString } from 'true-myth/result'; const double = n => n * 2;
const anOk = ok(12); const mappedOk = map(double, anOk); console.log(toString(mappedOk)); // Ok(24)
const anErr = err("nothing here!"); const mappedErr = map(double, anErr); console.log(toString(mappedOk)); // Err(nothing here!) ```
T The type of the value wrapped in an
Ok
instance, and taken as the argument to themapFn
. U The type of the value wrapped in the newOk
instance after applyingmapFn
, that is, the type returned bymapFn
. E The type of the value wrapped in anErr
instance.Parameter mapFn
The function to apply the value to if
result
isOk
.Parameter result
The
Result
instance to map over.Returns
A new
Result
with the result of applyingmapFn
to the value in anOk
, or else the originalErr
value wrapped in the new instance.
function mapErr
mapErr: { <T, E, F>(mapErrFn: (e: E) => F, result: Result<T, E>): Result<T, F>; <T, E, F>(mapErrFn: (e: E) => F): (result: Result<T, E>) => Result<T, F>;};
Map over a , exactly as in , but operating on the value wrapped in an instead of the value wrapped in the . This is handy for when you need to line up a bunch of different types of errors, or if you need an error of one shape to be in a different shape to use somewhere else in your codebase.
#### Examples
```ts import { ok, err, mapErr, toString } from 'true-myth/result';
const reason = (err: { code: number, reason: string }) => err.reason;
const anOk = ok(12); const mappedOk = mapErr(reason, anOk); console.log(toString(mappedOk)); // Ok(12)
const anErr = err({ code: 101, reason: 'bad file' }); const mappedErr = mapErr(reason, anErr); console.log(toString(mappedErr)); // Err(bad file) ```
T The type of the value wrapped in the
Ok
of theResult
. E The type of the value wrapped in theErr
of theResult
. F The type of the value wrapped in theErr
of a newResult
, returned by themapErrFn
.Parameter mapErrFn
The function to apply to the value wrapped in
Err
ifresult
is anErr
.Parameter result
The
Result
instance to map over an error case for.
function mapOr
mapOr: { <T, U, E>(orU: U, mapFn: (t: T) => U, result: Result<T, E>): U; <T, U, E>(orU: U, mapFn: (t: T) => U): (result: Result<T, E>) => U; <T, U, E>(orU: U): (mapFn: (t: T) => U) => (result: Result<T, E>) => U;};
Map over a instance as in [
map
](#map) and get out the value ifresult
is an , or return a default value ifresult
is an .#### Examples
```ts import { ok, err, mapOr } from 'true-myth/result';
const length = (s: string) => s.length;
const anOkString = ok('a string'); const theStringLength = mapOr(0, anOkString); console.log(theStringLength); // 8
const anErr = err('uh oh'); const anErrMapped = mapOr(0, anErr); console.log(anErrMapped); // 0 ```
Parameter orU
The default value to use if
result
is anErr
.Parameter mapFn
The function to apply the value to if
result
is anOk
.Parameter result
The
Result
instance to map over.
function mapOrElse
mapOrElse: { <T, U, E>(orElseFn: (err: E) => U, mapFn: (t: T) => U, result: Result<T, E>): U; <T, U, E>(orElseFn: (err: E) => U, mapFn: (t: T) => U): ( result: Result<T, E> ) => U; <T, U, E>(orElseFn: (err: E) => U): ( mapFn: (t: T) => U ) => (result: Result<T, E>) => U;};
Map over a instance as in and get out the value if
result
is , or apply a function (orElseFn
) to the value wrapped in the to get a default value.Like but using a function to transform the error into a usable value instead of simply using a default value.
#### Examples
```ts import { ok, err, mapOrElse } from 'true-myth/result';
const summarize = (s: string) =>
The response was: '${s}'
; const getReason = (err: { code: number, reason: string }) => err.reason;const okResponse = ok("Things are grand here."); const mappedOkAndUnwrapped = mapOrElse(getReason, summarize, okResponse); console.log(mappedOkAndUnwrapped); // The response was: 'Things are grand here.'
const errResponse = err({ code: 500, reason: 'Nothing at this endpoint!' }); const mappedErrAndUnwrapped = mapOrElse(getReason, summarize, errResponse); console.log(mappedErrAndUnwrapped); // Nothing at this endpoint! ```
T The type of the wrapped
Ok
value. U The type of the resulting value from applyingmapFn
to theOk
value ororElseFn
to theErr
value. E The type of the wrappedErr
value.Parameter orElseFn
The function to apply to the wrapped
Err
value to get a usable value ifresult
is anErr
.Parameter mapFn
The function to apply to the wrapped
Ok
value ifresult
is anOk
.Parameter result
The
Result
instance to map over.
function match
match: { <T, E, A>(matcher: Matcher<T, E, A>, result: Result<T, E>): A; <T, E, A>(matcher: Matcher<T, E, A>): (result: Result<T, E>) => A;};
Performs the same basic functionality as , but instead of simply unwrapping the value if it is and applying a value to generate the same default type if it is , lets you supply functions which may transform the wrapped type if it is
Ok
or get a default value forErr
.This is kind of like a poor man's version of pattern matching, which JavaScript currently lacks.
Instead of code like this:
```ts import Result, { isOk, match } from 'true-myth/result';
const logValue = (mightBeANumber: Result<number, string>) => { console.log( mightBeANumber.isOk ? mightBeANumber.value.toString() :
There was an error: ${unsafelyGetErr(mightBeANumber)}
); }; ```...we can write code like this:
```ts import Result, { match } from 'true-myth/result';
const logValue = (mightBeANumber: Result<number, string>) => { const value = match( { Ok: n => n.toString(), Err: e =>
There was an error: ${e}
, }, 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.
Parameter matcher
A lightweight object defining what to do in the case of each variant.
Parameter result
The
result
instance to check.Performs the same basic functionality as , but instead of simply unwrapping the value if it is and applying a value to generate the same default type if it is , lets you supply functions which may transform the wrapped type if it is
Ok
or get a default value forErr
.This is kind of like a poor man's version of pattern matching, which JavaScript currently lacks.
Instead of code like this:
```ts import Result, { isOk, match } from 'true-myth/result';
const logValue = (mightBeANumber: Result<number, string>) => { console.log( mightBeANumber.isOk ? mightBeANumber.value.toString() :
There was an error: ${unsafelyGetErr(mightBeANumber)}
); }; ```...we can write code like this:
```ts import Result, { match } from 'true-myth/result';
const logValue = (mightBeANumber: Result<number, string>) => { const value = match( { Ok: n => n.toString(), Err: e =>
There was an error: ${e}
, }, 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.
Parameter matcher
A lightweight object defining what to do in the case of each variant.
function or
or: { <T, E, F>(defaultResult: Result<T, F>, result: Result<T, E>): Result<T, F>; <T, E, F>(defaultResult: Result<T, F>): (result: Result<T, E>) => Result<T, F>;};
Provide a fallback for a given . Behaves like a logical
or
: if theresult
value is an , returns thatresult
; otherwise, returns thedefaultResult
value.This is useful when you want to make sure that something which takes a
Result
always ends up getting anOk
variant, by supplying a default value for the case that you currently have an .```ts import { ok, err, Result, or } from 'true-utils/result';
const okA = ok<string, string>('a'); const okB = ok<string, string>('b'); const anErr = err<string, string>(':wat:'); const anotherErr = err<string, string>(':headdesk:');
console.log(or(okB, okA).toString()); // Ok(A) console.log(or(anErr, okA).toString()); // Ok(A) console.log(or(okB, anErr).toString()); // Ok(B) console.log(or(anotherErr, anErr).toString()); // Err(:headdesk:) ```
T The type wrapped in the
Ok
case ofresult
. E The type wrapped in theErr
case ofresult
. F The type wrapped in theErr
case ofdefaultResult
.Parameter defaultResult
The
Result
to use ifresult
is anErr
.Parameter result
The
Result
instance to check.Returns
result
if it is anOk
, otherwisedefaultResult
.
function orElse
orElse: { <T, E, F>(elseFn: (err: E) => Result<T, F>, result: Result<T, E>): Result<T, F>; <T, E, F>(elseFn: (err: E) => Result<T, F>): ( result: Result<T, E> ) => Result<T, F>;};
Like , but using a function to construct the alternative .
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 fallbackResult<T>
. It can then transform the data in theErr
to something usable as an , or generate a new instance as appropriate.Useful for transforming failures to usable data.
Parameter elseFn
The function to apply to the contents of the
Err
ifresult
is anErr
, to create a newResult
.Parameter result
The
Result
to use if it is anOk
.Returns
The
result
if it isOk
, or theResult
returned byelseFn
ifresult
is an `Err.
function toJSON
toJSON: <T, E>(result: Result<T, E>) => ResultJSON<T, E>;
Create an
Object
representation of a instance.Useful for serialization.
JSON.stringify()
uses it.Parameter result
The value to convert to JSON
Returns
The JSON representation of the
Result
function toString
toString: <T, E>(result: Result<T, E>) => string;
Create a
String
representation of a instance.An instance will be
Ok(<representation of the value>)
, and an instance will beErr(<representation of the error>)
, where the representation of the value or error is simply the value or error's owntoString
representation. For example:call | output --------------------------------- | ----------------------
toString(ok(42))
|Ok(42)
toString(ok([1, 2, 3]))
|Ok(1,2,3)
toString(ok({ an: 'object' }))
|Ok([object Object])
ntoString(err(42))
|Err(42)
toString(err([1, 2, 3]))
|Err(1,2,3)
toString(err({ an: 'object' }))
|Err([object Object])
T The type of the wrapped value; its own
.toString
will be used to print the interior contents of theJust
variant.Parameter result
The value to convert to a string.
Returns
The string representation of the
Maybe
.
function tryOr
tryOr: { <T, E>(error: E, callback: () => T): Result<T, E>; <T, E>(error: E): (callback: () => T) => Result<T, E>;};
Execute the provided callback, wrapping the return value in or if there is an exception.
```ts const aSuccessfulOperation = () => 2 + 2;
const anOkResult = Result.tryOr('Oh noes!!1', () => { aSuccessfulOperation() }); // => Ok(4)
const thisOperationThrows = () => throw new Error('Bummer');
const anErrResult = Result.tryOr('Oh noes!!1', () => { thisOperationThrows(); }); // => Err('Oh noes!!1') ```
Parameter error
The error value in case of an exception
Parameter callback
The callback to try executing
function tryOrElse
tryOrElse: { <T, E>(onError: (e: unknown) => E, callback: () => T): Result<T, E>; <T, E>(onError: (e: unknown) => E): (callback: () => T) => Result<T, E>;};
Execute the provided callback, wrapping the return value in . If there is an exception, return a of whatever the
onError
function returns.```ts const aSuccessfulOperation = () => 2 + 2;
const anOkResult = Result.tryOrElse( (e) => e, aSuccessfulOperation ); // => Ok(4)
const thisOperationThrows = () => throw 'Bummer'
const anErrResult = Result.tryOrElse((e) => e, () => { thisOperationThrows(); }); // => Err('Bummer') ```
Parameter onError
A function that takes
e
exception and returns what will be wrapped in aResult.Err
Parameter callback
The callback to try executing
function unwrapOr
unwrapOr: { <T, U, E>(defaultValue: U, result: Result<T, E>): U | T; <T, U, E>(defaultValue: U): (result: Result<T, E>) => T | U;};
Safely get the value out of the variant of a .
This is the recommended way to get a value out of a
Result
most of the time.```ts import { ok, err, unwrapOr } from 'true-myth/result';
const anOk = ok<number, string>(12); console.log(unwrapOr(0, anOk)); // 12
const anErr = err<number, string>('nooooo'); console.log(unwrapOr(0, anErr)); // 0 ```
T The value wrapped in the
Ok
. E The value wrapped in theErr
.Parameter defaultValue
The value to use if
result
is anErr
.Parameter result
The
Result
instance to unwrap if it is anOk
.Returns
The content of
result
if it is anOk
, otherwisedefaultValue
.
function unwrapOrElse
unwrapOrElse: { <T, U, E>(orElseFn: (error: E) => U, result: Result<T, E>): T | U; <T, U, E>(orElseFn: (error: E) => U): (result: Result<T, E>) => T | U;};
Safely get the value out of a by returning the wrapped value if it is , or by applying
orElseFn
to the value in the .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 ).
```ts import { ok, err, unwrapOrElse } from 'true-myth/result';
// You can imagine that someOtherValue might be dynamic. const someOtherValue = 2; const handleErr = (errValue: string) => errValue.length + someOtherValue;
const anOk = ok<number, string>(42); console.log(unwrapOrElse(handleErr, anOk)); // 42
const anErr = err<number, string>('oh teh noes'); console.log(unwrapOrElse(handleErr, anErr)); // 13 ```
T The value wrapped in the
Ok
. E The value wrapped in theErr
.Parameter orElseFn
A function applied to the value wrapped in
result
if it is anErr
, to generate the final value.Parameter result
The
result
to unwrap if it is anOk
.Returns
The value wrapped in
result
if it isOk
or the value returned byorElseFn
applied to the value inErr
.
interface Err
interface Err<T, E> extends Omit<ResultImpl<T, E>, 'value' | 'cast'> {}
An
Err
instance is the *failure* variant instance of the type, representing a failure outcome from an operation which may fail. For a full discussion, see the module docs.T The type which would be wrapped in an
Ok
variant ofResult
. E The type wrapped in thisErr
variant ofResult
.
interface Ok
interface Ok<T, E> extends Omit<ResultImpl<T, E>, 'error' | 'cast'> {}
An
Ok
instance is the *successful* variant instance of the type, representing a successful outcome from an operation which may fail. For a full discussion, see the module docs.T The type wrapped in this
Ok
variant ofResult
. E The type which would be wrapped in anErr
variant ofResult
.
interface ResultConstructor
interface ResultConstructor {}
The public interface for the class *as a value*: the static constructors
ok
anderr
produce aResult
with that variant.
type Matcher
type Matcher<T, E, A> = { Ok: (value: T) => A; Err: (error: E) => A;};
A lightweight object defining how to handle each variant of a .
type Result
type Result<T, E> = Ok<T, E> | Err<T, E>;
type ResultJSON
type ResultJSON<T, E> = OkJSON<T> | ErrJSON<E>;
type Variant
type Variant = keyof typeof Variant;
namespace Toolbelt
module 'dist/es/toolbelt.d.ts' {}
Tools for working easily with
Maybe
andResult
*together*... but which do not *require* you to use both. If they were in thetrue-myth/maybe
ortrue-myth/result
modules, then importing either would always include the other. While that is not usually a concern with bundlers, it *is* an issue when using dynamic imports or otherwise doing runtime resolution in a browser or similar environment.The flip side of that is: importing from *this* module *does* require access to both
Maybe
andResult
modules.
function fromMaybe
fromMaybe: { <T, E>(errValue: E, maybe: Maybe<T>): Result<T, E>; <T, E>(errValue: E): (maybe: Maybe<T>) => Result<T, E>;};
Transform a into a .
If the
Maybe
is a , its value will be wrapped in the variant; if it is a theerrValue
will be wrapped in the variant.Parameter errValue
A value to wrap in an
Err
ifmaybe
is aNothing
.Parameter maybe
The
Maybe
to convert to aResult
.
function fromResult
fromResult: <T extends {}>(result: Result<T, unknown>) => Maybe<T>;
Construct a from a .
If the
Result
is anOk
, wrap its value inJust
. If theResult
is anErr
, throw away the wrappedE
and transform to a .T The type of the value wrapped in a
Result.Ok
and in theJust
of the resultingMaybe
.Parameter result
The
Result
to construct aMaybe
from.Returns
Just
ifresult
wasOk
orNothing
if it wasErr
.
function toMaybe
toMaybe: <T extends {}>(result: Result<T, unknown>) => Maybe<T>;
Convert a to a .
The converted type will be if the
Result
is or if theResult
is ; the wrapped error value will be discarded.Parameter result
The
Result
to convert to aMaybe
Returns
Just
the value inresult
if it isOk
; otherwiseNothing
function toOkOrElseErr
toOkOrElseErr: { <T, E>(elseFn: () => E, maybe: Maybe<T>): Result<T, E>; <T, E>(elseFn: () => E): (maybe: Maybe<T>) => Result<T, E>;};
Transform the into a , using the wrapped value as the
Ok
value ifJust
; otherwise usingelseFn
to generateErr
.T The wrapped value. E The error type to in the
Result
.Parameter elseFn
The function which generates an error of type
E
.Parameter maybe
The
Maybe
instance to convert.Returns
A
Result
containing the value wrapped inmaybe
in anOk
, or the value generated byelseFn
in anErr
.
function toOkOrErr
toOkOrErr: { <T, E>(error: E, maybe: Maybe<T>): Result<T, E>; <T, E>(error: E): (maybe: Maybe<T>) => Result<T, E>;};
Transform the into a , using the wrapped value as the
Ok
value ifJust
; otherwise using the suppliederror
value forErr
.T The wrapped value. E The error type to in the
Result
.Parameter error
The error value to use if the
Maybe
isNothing
.Parameter maybe
The
Maybe
instance to convert.Returns
A
Result
containing the value wrapped inmaybe
in anOk
, orerror
in anErr
.
function transposeMaybe
transposeMaybe: <T extends {}, E>( maybe: Maybe<Result<T, E>>) => Result<Maybe<T>, E>;
Transposes a of a into a
Result
of aMaybe
.| Input | Output | | -------------- | ------------- | |
Just(Ok(T))
|Ok(Just(T))
| |Just(Err(E))
|Err(E)
| |Nothing
|Ok(Nothing)
|Parameter maybe
a
Maybe<Result<T, E>>
to transform to aResult<Maybe<T>, E>>
.
function transposeResult
transposeResult: <T, E>(result: Result<Maybe<T>, E>) => Maybe<Result<T, E>>;
Transposes a of a into a
Maybe
of aResult
.| Input | Output | | ------------- | -------------- | |
Ok(Just(T))
|Just(Ok(T))
| |Err(E)
|Just(Err(E))
| |Ok(Nothing)
|Nothing
|Parameter result
a
Result<Maybe<T>, E>
to transform to aMaybe<Result<T, E>>
.
Package Files (5)
Dependencies (0)
No dependencies.
Dev Dependencies (11)
Peer Dependencies (0)
No peer dependencies.
Badge
To add a badge like this oneto your package's README, use the codes available below.
You may also use Shields.io to create a custom badge linking to https://www.jsdocs.io/package/true-myth
.
- Markdown[![jsDocs.io](https://img.shields.io/badge/jsDocs.io-reference-blue)](https://www.jsdocs.io/package/true-myth)
- HTML<a href="https://www.jsdocs.io/package/true-myth"><img src="https://img.shields.io/badge/jsDocs.io-reference-blue" alt="jsDocs.io"></a>
- Updated .
Package analyzed in 3629 ms. - Missing or incorrect documentation? Open an issue for this package.