tryad v1.0.0
tryad ·

Monadic mashup of Maybe & Either that represents a value, nothing, or an error.
There are a few major reasons for tryad to exist:
- most existing Maybe / Option / Either / Result types in JavaScript don't seamlessly interop with Promises
- if the Maybe contains an array, you have to
mapinside amapbecause it doesn't dispatch toMaybeandtoEitherbecome unnecessary if the type simply has a third branch to cover exceptions
So tryad attempts to create a new type that incorporates all of this - replacing
both null-ish checks and try/catch while working well with Promises.
installation
npm i tryadusage
import tryad from 'tryad'
import { resolve } from 'path'
const loadPlugin = atPath => {
return require(atPath).initialize()
}
const plugin = { name: 'a-plugin' /*, path: './plugin.js' */ }
const loaded = tryad(plugin.path)
.map(path => resolve(process.cwd(), path))
.try(absolute => loadPlugin(absolute))
.unwrap(
// `loaded` becomes equal to the return value of
// whichever branch we hit here in `unwrap`
Some => 'loaded the plugin'
None => 'plugin.path was not defined, so nothing was executed'
Fail => 'a wild error appeared! ' + Fail.message
)
// in this case `path` is not defined, so we get a `None`:
// -> 'plugin.path was not defined, so nothing was executed'Or if you're all about that async, let's check out Promises!
import tryad from 'tryad'
import { readJson } from 'fs-extra'
;(async () => {
const result = await tryad('./package.json')
// returning a Promise here like `readJson` does
// makes the chain's result become asynchronous
.try(path => readJson(path))
.map(pkg => pkg.keywords)
// methods dispatch to the inner value, so this
// maps over each keyword in the array
.map(key => key.toLowerCase())
.filter(key => key === 'maybe')
.unwrap(
Some => 'found the maybe keyword',
None => 'did not find the maybe keyword',
Fail => 'an error occurred! ' + Fail.message
)
/*...*/
})()And remember that if at any point a transformation causes a nil / falsy value
to be returned or if .try() throws an Error, the following transformations
will not be executed. This makes null handling very easy - in this case
the chain would 'skip forward' to the unwrap call.
api
tryad
tryad(value)Returns a new object that is either a None if value == null or a Some
containing value otherwise.
Expand the following sections to see the full documentation.
of
tryad.of(value)Alternate constructor that checks for truthiness rather than loose equality to null.
try
tryad.try(value, fn)Shortcut for tryad.of(value).try(fn). If value != null it will be applied
to the function fn, and any errors will be caught to transform the tryad
into a Fail. fn is only executed on a Some.
Arguments
value: anyfn: value -> anyFunction that will receive
valueas its only parameter. All errors are caught and returned in a newFailobject.
Returns
Some | None | Fail
async
tryad.async(value)Asynchronous version of the tryad constructor that accepts value as a
Promise, or wraps it in one if it isn't already a Promise.
async.of
tryad.async.of(value)Asynchronous version of the tryad.of constructor that accepts value as a
Promise, or wraps it in one if it isn't already a Promise.
isSomeLike
tryad.isSomeLike(value)Useful for checking if an arbitrary object is a Some, meaning
it is not == null and has an isSome method that returns true.
Arguments
value: any
Returns
Boolean
isNoneLike
tryad.isNoneLike(value)Useful for checking if an arbitrary object is a None, meaning
it is not == null and has an isNone method that returns true.
Arguments
value: any
Returns
Boolean
isFailLike
tryad.isFailLike(value)Useful for checking if an arbitrary object is a Fail, meaning
it is not == null and has an isFail method that returns true.
Arguments
value: any
Returns
Boolean
These methods are callable on instances of a Some, None, or Fail.
Examples will use the name box to represent one of these instances.
filter
box.filter(fn)fn will only be executed if box is a Some, and receives its value as its
only argument. If it returns falsy, a None will be returned. If it returns
truthy, the current instance is returned as-is. Dispatches to value.filter()
if it is callable.
Arguments
fn: (value) -> Boolean
Returns
Some | None
flatMap
box.flatMap(fn)fn will only be executed if box is a Some, and receives its value as its
only argument. Any returned tryad will be absorbed. Dispatches to value.flatMap()
if it is callable.
Arguments
fn: (value) -> Some | None | Fail
Returns
Some | None | Fail
forEach
box.forEach(fn)fn will only be executed if box is a Some, and receives its value as its
only argument. This method ends the chain. Dispatches to value.forEach() if
it is callable.
Arguments
fn: (value) -> any
Returns
undefined
includes
box.includes(other)If box is a Some, compares other against the value contained within box
and returns true if they are equal. Returns false if box is not a Some.
Dispatches to value.includes() if it is callable.
Returns
Boolean
map
box.map(fn)fn will only be executed if box is a Some, and receives its value as its
only argument. The return value will be used to construct a new tryad. If
fn will return a tryad, you probably want to use flatMap instead.
Dispatches to value.map() if it is callable.
Arguments
fn: (value) -> any
Returns
Some | None
orElse
box.orElse(fn)fn is only called if box is a None or a Fail. If box is a Fail,
fn will receive the error contained within.
Arguments
fn: (error?) -> any
Returns
Some | any
orSome
box.orSome(other)Returns the value contained within box if it is a Some, or returns
other if it is a None or a Fail. This method ends the chain.
Arguments
other: any
Returns
any
some
box.some()Returns the value contained within box. Throws if box is not a Some, so it's safer to use orSome. This method ends the chain.
Returns
any
try
box.try(fn)Attempts to call fn(value) and catches any error that occurs, returning a
Fail with the error. Not executed if box is not a Some.
Arguments
fn: value -> Some | None | Fail
Returns
Some | None | Fail
unwrap
box.unwrap(ifSome, ifNone, ifFail)Calls whichever function corresponds to the instance type and returns its value.
Arguments
ifSome: value -> anyifNone: () -> anyifFail: error -> any
Returns
any
see also
param.macro- Babel plugin for compile time partial application & lambda parameters
contributing
Pull requests and any issues found are always welcome.
- Fork the project, and preferably create a branch named something like
feat-make-better - Modify the source files as needed
- Make sure all tests continue to pass, and it never hurts to have more tests
- Push & pull request! :tada:
license
MIT © Bo Lingen / citycide
8 years ago