This adds an Option monad type for JavaScript.
The Option type is intended for cases where you sometimes might return a value (typically an object), and sometimes you might return no value (typically null) depending on arguments, or other runtime factors.
On one hand, the Option type forces a developer to consciously think about both cases (returning a value, or returning no value). That in itself will already make your code more robust. On the other hand, the Option type also allows the API developer to provide more concise API methods, and empowers the API user in how he consumes these methods.
Module can be easily installed with NPM:
npm install --save option-monad
Simply require it in your code:
const { Option } = require("option-monad");
Module consists of Option
facade function, and two concrete variants of an Option: Some
and None
constructors.
Option
type supports chaining of the standard set of transformations:
map(func: Any => Any): Option
flatMap(func: Any => Option): Option
filter(func: Any => Boolean): Option
filterNot(func: Any => Boolean): Option
select(val: Any): Option
reject(val: Any): Option
foldLeft(initial: T, func: Any => T): T
foldRight(initial: T, func: Any => T): T
It also has two methods for querying:
isDefined(): Boolean
isEmpty(): Boolean
Keep in mind, that not any of those methods will mutate the Option
instance they were called on.
Offers singular entry point to work with options. It is worth remembering that this is not a constructor, so it will throw Error
when called with a new
operator.
Function signature is:
function Option(value, noneValue = null) { ... }
, where value
is the value, that is going to be stored in an Option. You can also supply value to the noneValue
argument that will be used as a criteria of the None
case.
Offers a lazy zounterpart for the Option
type. Takes a callback and a set of arguments to apply to it. Will internally store those, up until the computation of the option result is required. Callback should return an instance of Option
(and, potentially, can return another LazyOption
).
IS a constructor. But possesses create
static method to create it's instance. IS an Iterable.
Possesses all of the Option
type's transformation and query methods (those are mapped to internal Option
that is a result of the callback
computation), plus it's own isResolved
method that exposes it's internal state.
let resultOne = Option(1); // will result in a Some instance
let resultTwo = Option(2, 2); // will result in a None instance
Both "Some", "None", and "LazyOption" instances are also considered instances of the "Option" type:
let someOpt = Option("value");
console.log(someOpt instanceof Some); // true
console.log(someOpt instanceof Option); // true
or
let noneOpt = Option(null);
console.log(noneOpt instanceof None); // true
console.log(noneOpt instanceof Option); // true
or
let lazy = LazyOption.create(() => Option(1));
console.log(lazy instanceof LazyOption); // true
console.log(lazy instanceof Option); // true
Option.fromReturn() method:
Signature:
Option.fromReturn(func, ...args);
Allows you to build on Option instance out of a function and a set of arguments to be passed to it:
let opt = Option.fromReturn((val1, val2) => { val1 * val2 }, 2, 20);
console.log(opt.get()); // 40
Option.ensure() method (v1.2.0):
Signature:
Option.ensure(val);
It will ensure, that any value given to it is an Option. If not - it will be wrapped into one:
let valueOne = "val",
valueTwo = Option("other");
Option.ensure(valueOne); // Some {}
Option.ensure(valueTwo); // Some {}
LazyOption (v1.5.0)
const lazy = LazyOption.create((foo, bar) => Option(foo + bar), "Foo", "Bar");
lazy.map(v => v.toUpperCase())
.filter(v => v.length > 0)
.getOrElse(""); // "FooBar"
const {Some, None} = require("option-monad");
function someFunc(criteria) {
let ret = someApi.getObject();
if (ret === criteria) {
return Some.create(ret); // You can also use "new Some(ret)" as well
}
// None is a singleton
return None.create();
}
You can be completely sure that such function will always return Option
type value.
let val = someFunc(true).get();
Will throw an Error
if the return value is None
.
let val = someFunc(true).getOrElse("fallback");
/* or ... */
let val = someFunc(true).getOrCall(() => { {foo: "fallback"} });
return someFunc(true)
.orElse(someOtherApi().getObject())
.orElse(someCrappyApi().getDefault());
return someFunc(true)
.orElse(LazyOption.create(() => someOtherApi().getObject());
You can make use of a couple of NPM scripts out there:
npm run lint
runs ESLint for library and test sourcesnpm test
runs Jest-powered testsnpm run build
runs both linting and tests