result-js
Rusty Monad Results for JS
Standard JS error management is done via throw
and try..catch
statements.
They, however, pose the risk that error opportunities are not handled by the user of an API,
hence pose the risk of fatal runtime errors.
In order to make a user aware of the risk of failure, monad error management was created.
One of the most prominent usages of such a result system is core::result::Result
of the programming language Rust.
This module is based on the Rust implementation, but brings some changes in order to better use it in JS.
One of the major differences is that result-js uses lowerCamelCase instead of snake_case.
Additionally, the methods ok()
, err()
and unwrapOrDefault()
were not implemented, since the former require a Option-dependency and the latter can easily be worked around by providing a default value yourself (using Result.or()
).
result-js
does not have any dependencies and conducts unit tests and coverage with TAP
and coveralls
.
You can find the complete API, as defined in code, below the examples!
Installation
npm i result-js --save
Simple Example
In the following example, you can see that the traditional way needs a lot more LoC, the type of myResult is not pinned and you might forget to use try..catch
.
The Result Monad helps to clean this mess up!
For more simple examples, please take a look at ./test.js
, on which Travis CI and Coveralls tests are based!
'use strict'; // Traditional way const syncButMightFail = { throw 'NaY!';}; let myResult = 'YaY';try myResult = ;catch$e console; // don't even care... // -------------------------------------// With Result const Result = ; const syncButMightFail = { return Result;}; const myResult = ;
Usage
Create new Result
'use strict'; const Result = ; const resultOk = Result;const resultErr = Result; // ...
Register Ok() and Err()
// ... // After the following line, Ok() and Err() will be available on a global level.// That means that you can do stuff, like// return Ok(val);// return Err('failed!');Result; // ...
Check if Error
// ... if resultOk || !resultOk console; if resultErr || !resultErr console;
Get Value
// ... // `unwrap` will throw if the Result is an Errorvar myResult = resultOk; // `expect` will also throw if the Result is an Error, but add a messagemyResult = resultOk; // `and` will return the passed value instead of the Ok-value if the Result is not an errormyResult = resultOk;myResult = resultOk; // `or` will return the passed value instead of the Result's error value in case the Result was an errormyResult = resultErr;myResult = resultErr; // Or just a very simple match, just what you already know from then-ables, like PromisesresultErr;
Control Flow
// ... console;// -> 4 console;// -> 9
API
All methods work just as described in the Rust documentation. The interface below includes Exceptions, however all methods are fully implemented and will not throw. The Exceptions are in place in order to provide you a clear, non-cluttered API overview.
/** * Rusty Result wrapper * * @type */moduleexports = /** * Create success Result with a return value. * * @param * @returns */ static { throw 'Not Implemented: Result.fromSuccess'; }; /** * Create error Result with a return value. * * @param * @returns */ static { throw 'Not Implemented: Result.fromError'; }; /** * Similar to Rust's `try!`, but only returns a * * @param * @returns */ static { throw 'Not Implemented: Result.fromTry'; }; /** * Register global convenience-functions Ok() and Err() */ static { throw 'Not Implemented: Result.registerGlobals'; }; /** * Returns true if the result is Ok. * * @returns */ { throw 'Not Implemented: Result.isOk'; }; /** * Returns true if the result is Err. * * @returns */ { throw 'Not Implemented: Result.isErr'; }; /** * Maps a Result<T, E> to Result<U, E> by applying a function to a contained Ok value, leaving an Err value untouched. * This function can be used to compose the results of two functions. * * @param * @returns */ { throw 'Not Implemented: Result.map'; }; /** * Maps a Result<T, E> to Result<T, F> by applying a function to a contained Err value, leaving an Ok value untouched. * This function can be used to pass through a successful result while handling an error. * * @param * @returns */ { throw 'Not Implemented: Result.mapErr'; }; /** * Returns an iterator over the possibly contained value. * The iterator yields one value if the result is Ok, otherwise none. * * @returns {Iterable.<*>} */ { throw 'Not Implemented: Result.iter'; }; /** * Returns `Ok(val)` if the result is Ok, otherwise returns `Err(err)` of itself. * * @param * @returns */ { throw 'Not Implemented: Result.and'; }; /** * Calls `resultEmitter` if the result is Ok, otherwise returns `Err(err)` value of itself. * This function can be used for control flow based on Result values. * * @param * @returns */ { throw 'Not Implemented: Result.andThen'; }; /** * Returns `Ok(val)` if the result is Err, otherwise returns `Ok(ok)` of itself. * * @param * @returns */ { throw 'Not Implemented: Result.or'; }; /** * Calls `resultEmitter` if the result is Err, otherwise returns the `Ok(ok)` value of itself. * This function can be used for control flow based on result values. * * @param * @returns */ { throw 'Not Implemented: Result.orElse'; }; /** * Unwraps a result, yielding the content of an Ok. * * @throws if the value is an Err, with a message provided by the Err's value. * @returns */ { throw 'Not Implemented: Result.unwrap'; }; /** * Unwraps a result, yielding the content of optb. Else it throws. * * @param * @return */ { throw 'Not Implemented: Result.unwrapAnd'; }; /** * Unwraps a result, calling valEmitter with its value. If the value is an Err then it throws. * * @param * @return */ { throw 'Not Implemented: Result.unwrapAndThen'; }; /** * Unwraps a result, yielding the content of an Err. * * @throws if the value is an Ok, with a custom panic message provided by the Ok's value. * @returns */ { throw 'Not Implemented: Result.unwrapErr'; }; /** * Unwraps a result, yielding the content of an Ok. Else it returns optb. * * @param * @return */ { throw 'Not Implemented: Result.unwrapOr'; }; /** * Unwraps a result, yielding the content of an Ok. If the value is an Err then it calls valEmitter with its value. * * @param * @return */ { throw 'Not Implemented: Result.unwrapOrElse'; }; /** * Unwraps a result, yielding the content of an Ok. * * @throws if the value is an Err, with a message including the passed message, and the content of the Err. * @param * @returns */ { throw 'Not Implemented: Result.expect'; }; /** * Unwraps a result, yielding the content of an Err. * * @throws if the value is an Ok, with a panic message including the passed message, and the content of the Ok. * @param * @returns */ { throw 'Not Implemented: Result.expectErr'; }; /** * JS convenience then-like handler (sync) * * @param * @param */ { throw 'Not Implemented: Result.match'; }; /** * JS convenience method to handle a result NodeJS-style * Example: * Result.fromError('uh oh!').node((err, val) => { * // do sth. * }); * * @param */ { throw 'Not Implemented: Result.node'; };; /** * This Callback is used to produce a final Result * * @callback ResultEmitter * @param * `val` will contain the result of {Result}. * @returns */ /** * This Callback is used to produce a final Value * * @callback ValueEmitter * @param * `val` will contain the result of {Result}. * @returns */ /** * This Callback is used as a return-handler * * @callback ResultHandler * @param * `ret` will either contain the result or the error, depending on the parameter position of the callback */ /** * This callback is used as NodeJS-style handler * * @callback NodeJSStyleHandler * @oaram * @param */