securityos/node_modules/true-myth/dist/cjs/maybe.js

922 lines
28 KiB
JavaScript
Raw Normal View History

2024-09-06 15:32:35 +00:00
"use strict";
/** [[include:doc/maybe.md]] */
Object.defineProperty(exports, "__esModule", { value: true });
/** (keep typedoc from getting confused by the imports) */
const Result = require("./result");
const utils_1 = require("./utils");
/**
Discriminant for the `Just` and `Nothing` variants.
You can use the discriminant via the `variant` property of `Maybe` instances
if you need to match explicitly on it.
*/
var Variant;
(function (Variant) {
Variant["Just"] = "Just";
Variant["Nothing"] = "Nothing";
})(Variant = exports.Variant || (exports.Variant = {}));
/**
A `Just` instance is the *present* variant instance of the
[`Maybe`](../modules/_maybe_.html#maybe) type, representing the presence of a
value which may be absent. For a full discussion, see [the module
docs](../modules/_maybe_.html).
@typeparam T The type wrapped in this `Just` variant of `Maybe`.
*/
class Just {
/**
Create an instance of `Maybe.Just` with `new`.
@note While you *may* create the `Just` type via normal JavaScript
class construction, it is not recommended for the functional style for
which the library is intended. Instead, use [`Maybe.of`] (for the general
case) or [`Maybe.just`] for this specific case.
[`Maybe.of`]: ../modules/_maybe_.html#of
[`Maybe.just`]: ../modules/_maybe_.html#just
```ts
// Avoid:
const aString = new Maybe.Just('characters');
// Prefer:
const aString = Maybe.just('characters);
```
@param value
The value to wrap in a `Maybe.Just`.
`null` and `undefined` are allowed by the type signature so that the
constructor may `throw` on those rather than constructing a type like
`Maybe<undefined>`.
@throws If you pass `null` or `undefined`.
*/
constructor(value) {
/** `Just` is always [`Variant.Just`](../enums/_maybe_.variant#just). */
this.variant = Variant.Just;
if (utils_1.isVoid(value)) {
throw new Error('Tried to construct `Just` with `null` or `undefined`');
}
this.value = value;
}
/**
Unwrap the contained value. A convenience method for functional idioms.
A common scenario where you might want to use this is in a pipeline of
functions:
```ts
import Maybe, { Just } from 'true-myth/maybe';
function getLengths(maybeStrings: Array<Maybe<string>>): Array<number> {
return maybeStrings
.filter(Maybe.isJust)
.map(Just.unwrap)
.map(s => s.length);
}
```
*/
static unwrap(theJust) {
return theJust.value;
}
/** Method variant for [`Maybe.isJust`](../modules/_maybe_.html#isjust) */
isJust() {
return true;
}
/** Method variant for [`Maybe.isNothing`](../modules/_maybe_.html#isnothing) */
isNothing() {
return false;
}
/** Method variant for [`Maybe.map`](../modules/_maybe_.html#map) */
map(mapFn) {
return map(mapFn, this);
}
/** Method variant for [`Maybe.mapOr`](../modules/_maybe_.html#mapor) */
mapOr(orU, mapFn) {
return mapOr(orU, mapFn, this);
}
/** Method variant for [`Maybe.mapOrElse`](../modules/_maybe_.html#maporelse) */
mapOrElse(orElseFn, mapFn) {
return mapOrElse(orElseFn, mapFn, this);
}
/** Method variant for [`Maybe.match`](../modules/_maybe_.html#match) */
match(matcher) {
return match(matcher, this);
}
/** Method variant for [`Maybe.or`](../modules/_maybe_.html#or) */
or(mOr) {
return or(mOr, this);
}
/** Method variant for [`Maybe.orElse`](../modules/_maybe_.html#orelse) */
orElse(orElseFn) {
return orElse(orElseFn, this);
}
/** Method variant for [`Maybe.and`](../modules/_maybe_.html#and) */
and(mAnd) {
return and(mAnd, this);
}
/** Method variant for [`Maybe.andThen`](../modules/_maybe_.html#andthen) */
andThen(andThenFn) {
return andThen(andThenFn, this);
}
/** Method variant for [`Maybe.chain`](../modules/_maybe_.html#chain) */
chain(chainFn) {
return this.andThen(chainFn);
}
/** Method variant for [`Maybe.flatMap`](../modules/_maybe_.html#flatmap) */
flatMap(flatMapFn) {
return this.andThen(flatMapFn);
}
/** Method variant for [`Maybe.unsafelyUnwrap`](../modules/_maybe_.html#unsafelyunwrap) */
unsafelyUnwrap() {
return this.value;
}
/** Method variant for [`Maybe.unwrapOr`](../modules/_maybe_.html#unwrapor) */
unwrapOr(defaultValue) {
return unwrapOr(defaultValue, this);
}
/** Method variant for [`Maybe.unwrapOrElse`](../modules/_maybe_.html#unwraporelse) */
unwrapOrElse(elseFn) {
return unwrapOrElse(elseFn, this);
}
/** Method variant for [`Maybe.toOkOrErr`](../modules/_maybe_.html#tookorerr) */
toOkOrErr(error) {
return toOkOrErr(error, this);
}
/** Method variant for [`Maybe.toOkOrElseErr`](../modules/_maybe_.html#tookorelseerr) */
toOkOrElseErr(elseFn) {
return toOkOrElseErr(elseFn, this);
}
/** Method variant for [`Maybe.toString`](../modules/_maybe_.html#tostring) */
toString() {
return toString(this);
}
/** Method variant for [`Maybe.toJSON`](../modules/_maybe_.html#toJSON) */
toJSON() {
return toJSON(this);
}
/** Method variant for [`Maybe.equals`](../modules/_maybe_.html#equals) */
equals(comparison) {
return equals(comparison, this);
}
/** Method variant for [`Maybe.ap`](../modules/_maybe_.html#ap) */
ap(val) {
return ap(this, val);
}
/**
Method variant for [`Maybe.get`](../modules/_maybe_.html#prop)
If you have a `Maybe` of an object type, you can do `thatMaybe.get('a key')`
to look up the next layer down in the object.
```ts
type DeepOptionalType = {
something?: {
with?: {
deeperKeys?: string;
}
}
};
const fullySet: DeepType = {
something: {
with: {
deeperKeys: 'like this'
}
}
};
const deepJust = Maybe.of(fullySet)
.get('something')
.get('with')
.get('deeperKeys');
console.log(deepJust); // Just('like this');
const partiallyUnset: DeepType = { something: { } };
const deepEmpty = Maybe.of(partiallyUnset)
.get('something')
.get('with')
.get('deeperKeys');
console.log(deepEmpty); // Nothing
```
*/
get(key) {
return this.andThen(property(key));
}
}
exports.Just = Just;
/**
A single instance of the `Nothing` object, to minimize memory usage. No matter
how many `Maybe`s are floating around, there will always be exactly and only
one `Nothing`.
@private
*/
let NOTHING;
/**
A `Nothing` instance is the *absent* variant instance of the
[`Maybe`](../modules/_maybe_.html#maybe) type, representing the presence of a
value which may be absent. For a full discussion, see [the module
docs](../modules/_maybe_.html).
@typeparam T The type which would be wrapped in a `Just` variant of `Maybe`.
*/
class Nothing {
/**
Create an instance of `Maybe.Nothing` with `new`.
@note While you *may* create the `Nothing` type via normal JavaScript
class construction, it is not recommended for the functional style for
which the library is intended. Instead, use [`Maybe.of`] (for the general
case) or [`Maybe.nothing`] for this specific case.
[`Maybe.of`]: ../modules/_maybe_.html#of
[`Maybe.nothing`]: ../modules/_maybe_.html#nothing
```ts
// Avoid:
const aNothing = new Maybe.Err();
// Prefer:
const aNothing = Maybe.nothing();
```
`null` and `undefined` are allowed so that you may explicitly construct the
`Err` type with a known `null` or `undefined` value. (This maybe helpful
primarily when transitioning a codebase to the use of `Maybe`.)
@throws If you pass `null` or `undefined`.
*/
constructor(_) {
/** `Nothing` is always [`Variant.Nothing`](../enums/_maybe_.variant#nothing). */
this.variant = Variant.Nothing;
if (!NOTHING) {
NOTHING = this;
}
return NOTHING;
}
/** Method variant for [`Maybe.isJust`](../modules/_maybe_.html#isjust) */
isJust() {
return false;
}
/** Method variant for [`Maybe.isNothing`](../modules/_maybe_.html#isnothing) */
isNothing() {
return true;
}
/** Method variant for [`Maybe.map`](../modules/_maybe_.html#map) */
map(mapFn) {
return map(mapFn, this);
}
/** Method variant for [`Maybe.mapOr`](../modules/_maybe_.html#mapor) */
mapOr(orU, mapFn) {
return mapOr(orU, mapFn, this);
}
/** Method variant for [`Maybe.mapOrElse`](../modules/_maybe_.html#maporelse) */
mapOrElse(orElseFn, mapFn) {
return mapOrElse(orElseFn, mapFn, this);
}
/** Method variant for [`Maybe.match`](../modules/_maybe_.html#match) */
match(matcher) {
return match(matcher, this);
}
/** Method variant for [`Maybe.or`](../modules/_maybe_.html#or) */
or(mOr) {
return or(mOr, this);
}
/** Method variant for [`Maybe.orElse`](../modules/_maybe_.html#orelse) */
orElse(orElseFn) {
return orElse(orElseFn, this);
}
/** Method variant for [`Maybe.and`](../modules/_maybe_.html#and) */
and(mAnd) {
return and(mAnd, this);
}
/** Method variant for [`Maybe.andThen`](../modules/_maybe_.html#andthen) */
andThen(andThenFn) {
return andThen(andThenFn, this);
}
/** Method variant for [`Maybe.chain`](../modules/_maybe_.html#chain) */
chain(chainFn) {
return this.andThen(chainFn);
}
/** Method variant for [`Maybe.flatMap`](../modules/_maybe_.html#flatmap) */
flatMap(flatMapFn) {
return this.andThen(flatMapFn);
}
/** Method variant for [`Maybe.unsafelyUnwrap`](../modules/_maybe_.html#unsafelyunwrap) */
unsafelyUnwrap() {
throw new Error('Tried to `unsafelyUnwrap(Nothing)`');
}
/** Method variant for [`Maybe.unwrapOr`](../modules/_maybe_.html#unwrapor) */
unwrapOr(defaultValue) {
return unwrapOr(defaultValue, this);
}
/** Method variant for [`Maybe.unwrapOrElse`](../modules/_maybe_.html#unwraporelse) */
unwrapOrElse(elseFn) {
return unwrapOrElse(elseFn, this);
}
/** Method variant for [`Maybe.toOkOrErr`](../modules/_maybe_.html#tookorerr) */
toOkOrErr(error) {
return toOkOrErr(error, this);
}
/** Method variant for [`Maybe.toOkOrElseErr`](../modules/_maybe_.html#tookorelseerr) */
toOkOrElseErr(elseFn) {
return toOkOrElseErr(elseFn, this);
}
/** Method variant for [`Maybe.toString`](../modules/_maybe_.html#tostring) */
toString() {
return toString(this);
}
/** Method variant for [`Maybe.toJSON`](../modules/_maybe_.html#toJSON) */
toJSON() {
return toJSON(this);
}
/** Method variant for [`Maybe.equals`](../modules/_maybe_.html#equals) */
equals(comparison) {
return equals(comparison, this);
}
/** Method variant for [`Maybe.ap`](../modules/_maybe_.html#ap) */
ap(val) {
return ap(this, val);
}
/**
Method variant for [`Maybe.get`](../modules/_maybe_.html#prop)
If you have a `Maybe` of an object type, you can do `thatMaybe.get('a key')`
to look up the next layer down in the object.
```ts
type DeepOptionalType = {
something?: {
with?: {
deeperKeys?: string;
}
}
};
const fullySet: DeepType = {
something: {
with: {
deeperKeys: 'like this'
}
}
};
const deepJust = Maybe.of(fullySet)
.get('something')
.get('with')
.get('deeperKeys');
console.log(deepJust); // Just('like this');
const partiallyUnset: DeepType = { something: { } };
const deepEmpty = Maybe.of(partiallyUnset)
.get('something')
.get('with')
.get('deeperKeys');
console.log(deepEmpty); // Nothing
```
*/
get(key) {
return this.andThen(property(key));
}
}
exports.Nothing = Nothing;
/**
Is this result a `Just` instance?
@typeparam T The type of the wrapped value.
@param maybe The `Maybe` instance to check.
@returns `true` if `maybe` is `Just`, `false` otherwise. In TypeScript,
also narrows the type from `Maybe<T>` to `Just<T>`.
*/
function isJust(maybe) {
return maybe.variant === Variant.Just;
}
exports.isJust = isJust;
/**
Is this result a `Nothing` instance?
@typeparam T The type of the wrapped value.
@param maybe The `Maybe` instance to check.
@returns `true` if `maybe` is `nothing`, `false` otherwise. In TypeScript,
also narrows the type from `Maybe<T>` to `Nothing<T>`.
*/
function isNothing(maybe) {
return maybe.variant === Variant.Nothing;
}
exports.isNothing = isNothing;
/**
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>`.
@typeparam T The type of the item contained in the `Maybe`.
@param value The value to wrap in a `Maybe.Just`.
@returns An instance of `Maybe.Just<T>`.
@throws If you pass `null` or `undefined`.
*/
function just(value) {
return new Just(value);
}
exports.just = just;
/**
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:
```ts
const notString = Maybe.nothing<string>();
```
@typeparam T The type of the item contained in the `Maybe`.
@returns An instance of `Maybe.Nothing<T>`.
*/
function nothing(_) {
if (!NOTHING)
NOTHING = new Nothing();
return NOTHING;
}
exports.nothing = nothing;
/**
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:
```ts
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).
@typeparam T The type of the item contained in the `Maybe`.
@param value 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.
*/
function of(value) {
return utils_1.isVoid(value) ? nothing() : just(value);
}
exports.of = of;
/**
Alias for [`of`](#of), convenient for a standalone import:
```ts
import { maybe } from 'true-myth/maybe';
interface Dict<T> {
[key: string]: T | null | undefined;
}
interface StrictDict<T> {
[key: string]: Maybe<T>;
}
function wrapNullables<T>(dict: Dict<T>): StrictDict<T> {
return Object.keys(dict).reduce((strictDict, key) => {
strictDict[key] = maybe(dict[key]);
return strictDict;
}, {} as StrictDict<T>);
}
```
*/
exports.maybe = of;
/** Alias for [`of`](#of), primarily for compatibility with Folktale. */
exports.fromNullable = of;
function map(mapFn, maybe) {
const op = (m) => (m.isJust() ? just(mapFn(m.value)) : nothing());
return utils_1.curry1(op, maybe);
}
exports.map = map;
function mapOr(orU, mapFn, maybe) {
function fullOp(fn, m) {
return m.isJust() ? fn(m.value) : orU;
}
function partialOp(fn, curriedMaybe) {
return curriedMaybe !== undefined
? fullOp(fn, curriedMaybe)
: (extraCurriedMaybe) => fullOp(fn, extraCurriedMaybe);
}
return mapFn === undefined
? partialOp
: maybe === undefined
? partialOp(mapFn)
: partialOp(mapFn, maybe);
}
exports.mapOr = mapOr;
function mapOrElse(orElseFn, mapFn, maybe) {
function fullOp(fn, m) {
return m.isJust() ? fn(m.value) : orElseFn();
}
function partialOp(fn, curriedMaybe) {
return curriedMaybe !== undefined
? fullOp(fn, curriedMaybe)
: (extraCurriedMaybe) => fullOp(fn, extraCurriedMaybe);
}
if (mapFn === undefined) {
return partialOp;
}
else if (maybe === undefined) {
return partialOp(mapFn);
}
else {
return partialOp(mapFn, maybe);
}
}
exports.mapOrElse = mapOrElse;
function and(andMaybe, maybe) {
const op = (m) => (m.isJust() ? andMaybe : nothing());
return utils_1.curry1(op, maybe);
}
exports.and = and;
function andThen(thenFn, maybe) {
const op = (m) => (m.isJust() ? thenFn(m.value) : nothing());
return maybe !== undefined ? op(maybe) : op;
}
exports.andThen = andThen;
/** Alias for [`andThen`](#andthen). */
exports.chain = andThen;
/** Alias for [`andThen`](#andthen). */
exports.flatMap = andThen;
/** Alias for [`andThen`](#andthen). */
exports.bind = andThen;
function or(defaultMaybe, maybe) {
const op = (m) => (m.isJust() ? m : defaultMaybe);
return maybe !== undefined ? op(maybe) : op;
}
exports.or = or;
function orElse(elseFn, maybe) {
const op = (m) => (m.isJust() ? m : elseFn());
return utils_1.curry1(op, maybe);
}
exports.orElse = orElse;
/**
Get the value out of the `Maybe`.
Returns the content of a `Just`, but **throws if the `Maybe` is `Nothing`**.
Prefer to use [`unwrapOr`](#unwrapor) or [`unwrapOrElse`](#unwraporelse).
@typeparam T The type of the wrapped value.
@param maybe The value to unwrap
@returns The unwrapped value if the `Maybe` instance is `Just`.
@throws If the `maybe` is `Nothing`.
*/
function unsafelyUnwrap(maybe) {
return maybe.unsafelyUnwrap();
}
exports.unsafelyUnwrap = unsafelyUnwrap;
/** Alias for [`unsafelyUnwrap`](#unsafelyunwrap) */
exports.unsafelyGet = unsafelyUnwrap;
/** Alias for [`unsafelyUnwrap`](#unsafelyunwrap) */
exports.unsafeGet = unsafelyUnwrap;
function unwrapOr(defaultValue, maybe) {
const op = (m) => (m.isJust() ? m.value : defaultValue);
return utils_1.curry1(op, maybe);
}
exports.unwrapOr = unwrapOr;
/** Alias for [`unwrapOr`](#unwrapor) */
exports.getOr = unwrapOr;
function unwrapOrElse(orElseFn, maybe) {
const op = (m) => (m.isJust() ? m.value : orElseFn());
return utils_1.curry1(op, maybe);
}
exports.unwrapOrElse = unwrapOrElse;
/** Alias for [`unwrapOrElse`](#unwraporelse) */
exports.getOrElse = unwrapOrElse;
function toOkOrErr(error, maybe) {
const op = (m) => (m.isJust() ? Result.ok(m.value) : Result.err(error));
return maybe !== undefined ? op(maybe) : op;
}
exports.toOkOrErr = toOkOrErr;
function toOkOrElseErr(elseFn, maybe) {
const op = (m) => (m.isJust() ? Result.ok(m.value) : Result.err(elseFn()));
return utils_1.curry1(op, maybe);
}
exports.toOkOrElseErr = toOkOrElseErr;
/**
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`.
@typeparam T The type of the value wrapped in a `Result.Ok` and in the `Just`
of the resulting `Maybe`.
@param result The `Result` to construct a `Maybe` from.
@returns `Just` if `result` was `Ok` or `Nothing` if it was `Err`.
*/
function fromResult(result) {
return result.isOk() ? just(result.value) : nothing();
}
exports.fromResult = fromResult;
/**
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` |
@typeparam T The type of the wrapped value; its own `.toString` will be used
to print the interior contents of the `Just` variant.
@param maybe The value to convert to a string.
@returns The string representation of the `Maybe`.
*/
function toString(maybe) {
const body = maybe.isJust() ? `(${maybe.value.toString()})` : '';
return `${maybe.variant}${body}`;
}
exports.toString = toString;
/**
* Create an `Object` representation of a `Maybe` instance.
*
* Useful for serialization. `JSON.stringify()` uses it.
*
* @param maybe The value to convert to JSON
* @returns The JSON representation of the `Maybe`
*/
function toJSON(maybe) {
return maybe.isJust()
? { variant: maybe.variant, value: maybe.value }
: { variant: maybe.variant };
}
exports.toJSON = toJSON;
function match(matcher, maybe) {
return maybe !== undefined
? mapOrElse(matcher.Nothing, matcher.Just, maybe)
: (curriedMaybe) => mapOrElse(matcher.Nothing, matcher.Just, curriedMaybe);
}
exports.match = match;
/** Alias for [`match`](#match) */
exports.cata = match;
function equals(mb, ma) {
return ma !== undefined
? ma.match({
Just: aVal => mb.isJust() && mb.unsafelyUnwrap() === aVal,
Nothing: () => isNothing(mb),
})
: (maybeA) => maybeA.match({
Nothing: () => isNothing(mb),
Just: aVal => mb.isJust() && mb.unsafelyUnwrap() === aVal,
});
}
exports.equals = equals;
function ap(maybeFn, maybe) {
const op = (m) => m.match({
Just: val => maybeFn.map(fn => fn(val)),
Nothing: () => nothing(),
});
return utils_1.curry1(op, maybe);
}
exports.ap = ap;
/**
Determine whether an item is an instance of `Just` or `Nothing`.
@param item The item to check.
*/
function isInstance(item) {
return item instanceof Just || item instanceof Nothing;
}
exports.isInstance = isInstance;
function find(predicate, array) {
const op = (a) => exports.maybe(a.find(predicate));
return utils_1.curry1(op, array);
}
exports.find = find;
/**
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
```ts
let empty = [];
Maybe.head(empty); // => Nothing
let full = [1, 2, 3];
Maybe.head(full); // => Just(1)
```
@param array The array to get the first item from.
*/
function head(array) {
return exports.maybe(array[0]);
}
exports.head = head;
/** A convenience alias for `Maybe.head`. */
exports.first = head;
/**
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
```ts
let empty = [];
Maybe.last(empty); // => Nothing
let full = [1, 2, 3];
Maybe.last(full); // => Just(3)
```
@param array The array to get the first item from.
*/
function last(array) {
return exports.maybe(array[array.length - 1]);
}
exports.last = last;
/**
Convert the arguments to a single `Maybe`. Useful for dealing with arrays of
`Maybe`s, via the spread operator.
## Examples
```ts
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.
@param maybes The `Maybe`s to resolve to a single `Maybe`.
*/
function all(...maybes) {
let result = just([]);
maybes.forEach(maybe => {
result = result.andThen(accumulatedMaybes => maybe.map(m => {
accumulatedMaybes.push(m);
return accumulatedMaybes;
}));
});
return result;
}
exports.all = all;
function tuple(maybes) {
// @ts-ignore -- this doesn't type-check, but it works correctly.
return all(...maybes);
}
exports.tuple = tuple;
function property(key, obj) {
const op = (a) => exports.maybe(a[key]);
return utils_1.curry1(op, obj);
}
exports.property = property;
function get(key, maybeObj) {
return utils_1.curry1(exports.bind(property(key)), maybeObj);
}
exports.get = get;
/**
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`:
```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 `||` 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:
```ts
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`:
```ts
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');
```
@param fn The function to transform; the resulting function will have the
exact same signature except for its return type.
*/
function wrapReturn(fn) {
return (...args) => of(fn(...args));
}
exports.wrapReturn = wrapReturn;
/** Alias for [`wrapReturn`](#wrapReturn). */
exports.maybeify = wrapReturn;
exports.transmogrify = wrapReturn;
exports.Maybe = {
Variant,
Just,
Nothing,
all,
isJust,
isNothing,
just,
nothing,
of,
find,
first: exports.first,
fromNullable: exports.fromNullable,
head,
last,
map,
mapOr,
mapOrElse,
and,
andThen,
chain: exports.chain,
flatMap: exports.flatMap,
or,
orElse,
unsafelyUnwrap,
unsafelyGet: exports.unsafelyGet,
unsafeGet: exports.unsafeGet,
unwrapOr,
getOr: exports.getOr,
unwrapOrElse,
getOrElse: exports.getOrElse,
toOkOrErr,
toOkOrElseErr,
fromResult,
toString,
toJSON,
tuple,
match,
cata: exports.cata,
equals,
ap,
isInstance,
property,
get,
wrapReturn,
ify: wrapReturn,
};
exports.default = exports.Maybe;
//# sourceMappingURL=maybe.js.map