UNPKG

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
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 };