monads-co
Version:
An implementation of Haskell's type classes in TS
166 lines • 4.39 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Err = exports.Ok = exports.Result = void 0;
const Monad_1 = require("./Monad");
const Optional_1 = require("./Optional");
class Result extends Monad_1.Monad {
_success;
_value;
constructor(_success, _value) {
super();
this._success = _success;
this._value = _value;
}
/**
* Used to wrap a potential error throwing function into a safe Result wrapped function. Usage looks like:
* ```ts
* const safeJsonParse = Result.wrap<typeof JSON.parse, SyntaxError>(JSON.parse)
* ```
* @param fn
*/
static wrap(fn) {
return (...args) => {
try {
return Ok(fn(...args));
}
catch (e) {
return Err(e);
}
};
}
/**
* If Ok, this uses the mapping function to transform Value to a new Value, and returns Result<New Value, ErrorT>
* otherwise it propagates the ErrorT.
* @param mapping
*/
map(mapping) {
if (this._success) {
return Ok(mapping(this._value));
}
else {
return Err(this._value);
}
}
amap(mapping) {
if (this._success) {
if (mapping._success) {
return Ok(mapping._value(this._value));
}
}
if (!mapping._success) {
return Err(mapping._value);
}
return Err(this._value);
}
pure(value) {
return Ok(value);
}
/**
* If Ok, the mapping of ValueT to a Result is run, otherwise the Error is propagated. If you want to just transform
* ValueT to a new Value, use `.map`
* @param mapping
*/
then(mapping) {
if (this._success) {
return mapping(this._value);
}
return Err(this._value);
}
// Result specific methods
/**
* Returns the ValueT if Ok, otherwise it returns `defaultValue`
* @param defaultValue
*/
or(defaultValue) {
if (this._success) {
return this._value;
}
return defaultValue;
}
/**
* If Err this runs the mapping from ErrorT => ValueT, otherwise it returns a new Result containing ValueT
* @param mapping
*/
catch(mapping) {
if (this._success) {
return Ok(this._value);
}
return Ok(mapping(this._value));
}
/**
* If Err this runs the mapping from ErrorT => Result<ValueT, NewErrorT>, otherwise it returns a new Result containing
* ValueT
* @param mapping
*/
catchThen(mapping) {
if (this._success) {
return Ok(this._value);
}
return mapping(this._value);
}
/**
* Returns the ValueT if Ok, otherwise it throws ErrorT. This is the nuclear option, `.or(default)` should be preferred.
*/
unwrap() {
if (this._success) {
return this._value;
}
// Kaboom, functional land just died :(
throw this._value;
}
/**
* Converts a Result<ValueT, ErrorT> to an Optional<ValueT>
*/
toOptional() {
if (this._success) {
return (0, Optional_1.Some)(this._value);
}
else {
return (0, Optional_1.None)();
}
}
}
exports.Result = Result;
/**
* Used to construct an Ok value, for example:
*
* @example
* ```ts
* type ErrorMessage = string
*
* function safeDivide(a: number, b: number): Result<number, ErrorMessage> {
* if (b === 0) {
* return Err("Can't divide by zero")
* } else {
* return Ok(a / b)
* }
* }
* ```
* @param value
*/
function Ok(value) {
return new Result(true, value);
}
exports.Ok = Ok;
/**
* Used to construct an Err value, for example:
*
* @example
* ```ts
* type ErrorMessage = string
*
* function safeDivide(a: number, b: number): Result<number, ErrorMessage> {
* if (b === 0) {
* return Err("Can't divide by zero")
* } else {
* return Ok(a / b)
* }
* }
* ```
* @param value
*/
function Err(value) {
return new Result(false, value);
}
exports.Err = Err;
//# sourceMappingURL=Result.js.map