option-t
Version:
A toolkit of Nullable/Option/Result type implementation in ECMAScript. Their APIs are inspired by Rust's `Option<T>` and `Result<T, E>`.
321 lines (320 loc) • 9.95 kB
JavaScript
import { createClassicSome, createClassicNone, } from '../classic_option/classic_option.js';
/**
* @deprecated
* See https://github.com/option-t/option-t/issues/459
*
* XXX:
* This is only used for the instanceof-basis runtime checking. (e.g. `React.PropTypes.instanceOf()`)
* You MUST NOT use for other purpose.
*/
export class ClassicResultBase {
constructor(ok, val, err) {
this._isOk = ok;
this._v = val;
this._e = err;
Object.seal(this);
}
/**
* Returns true if the result is `Ok`.
*/
isOk() {
return this._isOk;
}
/**
* Returns true if the result is `Err`.
*/
isErr() {
return !this._isOk;
}
/**
* Converts from `Result<T, E>` to `Option<T>`.
* If the self is `Ok`, returns `Some<T>`.
* Otherwise, returns `None<T>`.
*
* @return {!OptionT<T>}
*/
ok() {
if (this._isOk) {
// This code is required to keep backward compatibility.
// @ts-expect-error
return createClassicSome(this._v);
}
else {
return createClassicNone();
}
}
/**
* Converts from `Result<T, E>` to `Option<E>`.
* If the self is `Err`, returns `Some<E>`.
* Otherwise, returns `None<E>`.
*
* @return {!OptionT<E>}
*/
err() {
if (!this._isOk) {
// This code is required to keep backward compatibility.
// @ts-expect-error
return createClassicSome(this._e);
}
else {
return createClassicNone();
}
}
/**
* Maps a `Result<T, E>` to `Result<U, E>` by applying a function `mapFn<T, U>`
* to an contained `Ok` value, leaving an `Err` value untouched.
*
* This function can be used to compose the results of two functions.
*/
map(op) {
if (!this._isOk) {
// cheat to escape from a needless allocation.
// @ts-expect-error
return this;
}
// This code is required to keep backward compatibility.
// @ts-expect-error
const value = op(this._v);
const result = createClassicOk(value);
return result;
}
/**
* Maps a `Result<T, E>` to `U` by applying a function to a contained `Ok` value,
* or a `fallback` function to a contained `Err` value.
* This function can be used to unpack a successful result while handling an error.
*/
mapOrElse(fallback, selector) {
if (!this._isOk) {
// This code is required to keep backward compatibility.
// @ts-expect-error
const r = fallback(this._e);
return r;
}
// This code is required to keep backward compatibility.
// @ts-expect-error
const r = selector(this._v);
return r;
}
/**
* Maps a `Result<T, E>` to `Result<T, F>` by applying a function `mapFn<E, F>`
* to an contained `Err` value, leaving an `Ok` value untouched.
*
* This function can be used to pass through a successful result while handling an error.
*/
mapErr(op) {
if (this._isOk) {
// cheat to escape from a needless allocation.
// @ts-expect-error
return this;
}
// This code is required to keep backward compatibility.
// @ts-expect-error
const value = op(this._e);
const result = createClassicErr(value);
return result;
}
/**
* Returns `res` if the result is `Ok`, otherwise returns the `Err` value of self.
*/
and(res) {
if (this._isOk) {
return res;
}
else {
// cheat to escape from a needless allocation.
// @ts-expect-error
return this;
}
}
/**
* Calls `op` if the result is `Ok`, otherwise returns the `Err` value of self.
* This function can be used for control flow based on result values.
*/
andThen(op) {
if (!this._isOk) {
// cheat to escape from a needless allocation.
// @ts-expect-error
return this;
}
// This code is required to keep backward compatibility.
// @ts-expect-error
const mapped = op(this._v);
const isResult = mapped instanceof ClassicResultBase;
if (!isResult) {
throw new TypeError("Result<T, E>.andThen()' param `op` should return `Result<U, E>`.");
}
return mapped;
}
/**
* Returns `res` if the result is `Err`, otherwise returns the `Ok` value of self.
*/
or(res) {
if (this._isOk) {
// cheat to escape from a needless allocation.
// @ts-expect-error
return this;
}
else {
return res;
}
}
/**
* Calls `op` if the result is `Err`, otherwise returns the `Ok` value of self.
* This function can be used for control flow based on result values.
*/
orElse(op) {
if (this._isOk) {
// cheat to escape from a needless allocation.
// @ts-expect-error
return this;
}
// This code is required to keep backward compatibility.
// @ts-expect-error
const mapped = op(this._e);
const isResult = mapped instanceof ClassicResultBase;
if (!isResult) {
throw new TypeError("Result<T, E>.orElse()' param `op` should return `Result<T, F>`.");
}
return mapped;
}
/**
* Return the inner `T` of a `Ok(T)`.
*
* @throws {TypeError}
* Throws if the self is a `Err`.
*/
unwrap() {
return this.expect('called `unwrap()` on a `Err` value');
}
/**
* Return the inner `E` of a `Err(E)`.
*
* @throws {TypeError}
* Throws if the self is a `Ok`.
*/
unwrapErr() {
if (this._isOk) {
throw new TypeError('called `unwrapErr()` on a `Ok` value');
}
else {
// This code is required to keep backward compatibility.
// @ts-expect-error
return this._e;
}
}
/**
* Unwraps a result, return the content of an `Ok`. Else it returns `optb`.
*/
unwrapOr(optb) {
if (this._isOk) {
// This code is required to keep backward compatibility.
// @ts-expect-error
return this._v;
}
else {
return optb;
}
}
/**
* Unwraps a result, returns the content of an `Ok`.
* If the value is an `Err` then it calls `op` with its value.
*/
unwrapOrElse(op) {
if (this._isOk) {
// This code is required to keep backward compatibility.
// @ts-expect-error
return this._v;
}
// This code is required to keep backward compatibility.
// @ts-expect-error
const recovered = op(this._e);
return recovered;
}
/**
* Return the inner `T` of a `Ok(T)`.
*
* @throws {TypeError}
* Throws the passed `message` if the self is a `Err`.
*/
expect(message) {
if (this._isOk) {
// This code is required to keep backward compatibility.
// @ts-expect-error
return this._v;
}
else {
throw new TypeError(message);
}
}
/**
* The destructor method inspired by Rust's `Drop` trait.
* We don't define the object's behavior after calling this.
*
* @param destructor
* This would be called with the inner value if self is `Ok<T>`.
* @param errDestructor
* This would be called with the inner value if self is `Err<E>`.
*/
drop(destructor, errDestructor) {
if (this._isOk) {
if (typeof destructor === 'function') {
// This code is required to keep backward compatibility.
// @ts-expect-error
destructor(this._v);
}
// This code is required to keep backward compatibility.
// @ts-expect-error
this._v = null;
}
else {
if (typeof errDestructor === 'function') {
// This code is required to keep backward compatibility.
// @ts-expect-error
errDestructor(this._e);
}
// This code is required to keep backward compatibility.
// @ts-expect-error
this._e = null;
}
Object.freeze(this);
}
}
Object.freeze(ClassicResultBase.prototype);
/**
* @deprecated
* See https://github.com/option-t/option-t/issues/459
*/
export function createClassicOk(val) {
// This code is required to keep backward compatibility.
// @ts-expect-error
const o = new ClassicResultBase(true, val, undefined);
return o;
}
/**
* @deprecated
* See https://github.com/option-t/option-t/issues/459
*/
export function createClassicErr(err) {
// This code is required to keep backward compatibility.
// @ts-expect-error
const o = new ClassicResultBase(false, undefined, err);
return o;
}
/**
* @deprecated
* See https://github.com/option-t/option-t/issues/459
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
export const ClassicOkConstructor = function ClassicOkConstructor(val) {
return createClassicOk(val);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
};
/**
* @deprecated
* See https://github.com/option-t/option-t/issues/459
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
export const ClassicErrConstructor = function ClassicErrConstructor(err) {
return createClassicErr(err);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
};