resulty
Version:
A disjunction implementation in TypeScript.
239 lines (232 loc) • 6.47 kB
JavaScript
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
// src/index.ts
var Result = class _Result {
constructor(state) {
this.state = state;
}
/**
* Construct a successful result
* @param value a value to wrap in Ok
* @returns a new Result with the value wrapped in Ok
*/
static ok(value) {
return new _Result({ kind: "ok", value });
}
/**
* Construct a failed result
* @param error a value to wrap in Err
* @returns a new Result with the value wrapped in Err
*/
static err(error) {
return new _Result({ kind: "err", error });
}
/**
* Returns true if the result is a success
*/
isOk() {
return this.state.kind === "ok";
}
/**
* Returns true if the result is a failure
*/
isErr() {
return this.state.kind === "err";
}
/**
* Returns the value from a successful result. For an error, returns the
* result of evaluating the fn
*/
getOrElse(fn) {
switch (this.state.kind) {
case "ok":
return this.state.value;
case "err":
return fn();
}
}
/**
* Returns the value from a successful result. Returns the defaultValue if
* the result was a failure.
*/
getOrElseValue(defaultValue) {
switch (this.state.kind) {
case "ok":
return this.state.value;
case "err":
return defaultValue;
}
}
/**
* Returns a new result after applying fn to the value stored in a successful
* result. If the result was a failure, then the Err result is simply
* returned.
*/
map(fn) {
switch (this.state.kind) {
case "ok":
return _Result.ok(fn(this.state.value));
case "err":
return _Result.err(this.state.error);
}
}
/**
* An alias for `map`
*/
and(fn) {
return this.map(fn);
}
/**
* Returns a new result after applying fn to the error value. successful
* results are returned unchanged.
*/
mapError(fn) {
switch (this.state.kind) {
case "ok":
return _Result.ok(this.state.value);
case "err":
return _Result.err(fn(this.state.error));
}
}
/**
* Chains together two computations that return results. If the result is a
* success, then the second computation is run. Otherwise, the Err is
* returned.
*/
andThen(fn) {
switch (this.state.kind) {
case "ok":
return fn(this.state.value);
case "err":
return _Result.err(this.state.error);
}
}
/**
* Runs an alternative computation in the case that the first computation
* resulted in an Err.
*/
orElse(fn) {
switch (this.state.kind) {
case "ok":
return _Result.ok(this.state.value);
case "err":
return fn(this.state.error);
}
}
/**
* Folds over types; a switch/case for success or failure.
*/
cata(matcher) {
switch (this.state.kind) {
case "ok":
return matcher.Ok(this.state.value);
case "err":
return matcher.Err(this.state.error);
}
}
/**
* Encapsulates a common pattern of needing to build up an Object from
* a series of Result values. This is often solved by nesting `andThen` calls
* and then completing the chain with a call to `ok`.
*
* This feature was inspired (and the code lifted from) this article:
* https://medium.com/@dhruvrajvanshi/simulating-haskells-do-notation-in-typescript-e48a9501751c
*
* Wrapped values are converted to an Object using the Object constructor
* before assigning. Primitives won't fail at runtime, but results may
* be unexpected.
*/
assign(k, other) {
const state = this.state;
switch (state.kind) {
case "ok": {
const result = typeof other === "function" ? other(state.value) : other;
return result.map((b) => __spreadProps(__spreadValues({}, Object(state.value)), {
[k.toString()]: b
}));
}
case "err":
return _Result.err(state.error);
}
}
/**
* Inject a side-effectual operation into a chain of Result computations.
*
* The primary use case for `do` is to perform logging in the middle of a flow
* of Results.
*
* The side effect only runs when there isn't an error (Ok).
*
* The value will (should) remain unchanged during the `do` operation.
*
* ok({})
* .assign('foo', ok(42))
* .assign('bar', ok('hello'))
* .do(scope => console.log('Scope: ', JSON.stringify(scope)))
* .map(doSomethingElse)
*
*/
do(fn) {
switch (this.state.kind) {
case "ok":
fn(this.state.value);
return this;
case "err":
return this;
}
}
/**
* Inject a side-effectual operation into a chain of Result computations.
*
* The side effect only runs when there is an error (Err).
*
* The value will remain unchanged during the `elseDo` operation.
*
* ok({})
* .assign('foo', ok(42))
* .assign('bar', err('hello'))
* .elseDo(scope => console.log('Scope: ', JSON.stringify(scope)))
* .map(doSomethingElse)
*
*/
elseDo(fn) {
switch (this.state.kind) {
case "ok":
return this;
case "err":
fn(this.state.error);
return this;
}
}
};
function ok(value) {
return Result.ok(value);
}
function err(error) {
return Result.err(error);
}
function isOk(result) {
return result.isOk();
}
function isErr(result) {
return result.isErr();
}
exports.Result = Result; exports.err = err; exports.isErr = isErr; exports.isOk = isOk; exports.ok = ok;
//# sourceMappingURL=index.cjs.map