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>`.
256 lines (255 loc) • 7.59 kB
JavaScript
/**
* @deprecated
* See https://github.com/option-t/option-t/issues/459
*
* The base object of `Some<T>` and `None<T>`.
*
* XXX:
* In general case, __we must not use this base object__.
* __Use `Option<T>` interface strongly__.
*
* You can only this object if you need to cooperate with some libralies
* like `React.PropTypes` which are use `instanceof` checking to work together with
* others in the pure JavaScript world.
*
* The typical case is TSX (TypeScript JSX) syntax.
* https://github.com/Microsoft/TypeScript/wiki/JSX
*
* Our basic stance is that _you don't use this and need not it in almost case_.
*
* See also:
* https://github.com/option-t/option-t/pull/77
*/
export class ClassicOptionBase {
constructor(ok, val) {
this.ok = ok;
this.val = val;
Object.seal(this);
}
/**
* Return whether this is `Some<T>` or not.
*/
get isSome() {
return this.ok;
}
/**
* Return whether this is `None` or not.
*/
get isNone() {
return !this.ok;
}
/**
* Returns the inner `T` of a `Some<T>`.
* @throws {TypeError}
* Throws if the self value equals `None`.
*/
unwrap() {
if (!this.ok) {
throw new TypeError('called `unwrap()` on a `None` value');
}
// This code is required to keep backward compatibility.
// @ts-expect-error
return this.val;
}
/**
* Returns the contained value or a default value `def`.
*/
unwrapOr(def) {
// This code is required to keep backward compatibility.
// @ts-expect-error
return this.ok ? this.val : def;
}
/**
* Returns the contained value or computes it from a closure `fn`.
*/
unwrapOrElse(fn) {
// This code is required to keep backward compatibility.
// @ts-expect-error
return this.ok ? this.val : fn();
}
/**
* Returns the inner `T` of a `Some<T>`.
* @throws {TypeError}
* Throws a custom error with provided `msg`
* if the self value equals `None`.
*/
expect(msg) {
if (!this.ok) {
throw new TypeError(msg);
}
// This code is required to keep backward compatibility.
// @ts-expect-error
return this.val;
}
/**
* Maps an `Option<T>` to `Option<U>` by applying a function to a contained value.
*/
map(fn) {
if (!this.ok) {
// 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 = fn(this.val);
const option = createClassicSome(value);
return option;
}
/**
* Returns `None` if the self is `None`,
* otherwise calls `fn` with the wrapped value and returns the result.
*/
flatMap(fn) {
if (!this.ok) {
// 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 = fn(this.val);
const isOption = mapped instanceof ClassicOptionBase;
if (!isOption) {
throw new TypeError("Option<T>.flatMap()' param `fn` should return `Option<T>`.");
}
return mapped;
}
/**
* Applies a function `fn` to the contained value or returns a default `def`.
*/
mapOr(def, fn) {
if (this.ok) {
// This code is required to keep backward compatibility.
// @ts-expect-error
return fn(this.val);
}
else {
return def;
}
}
/**
* Applies a function `fn` to the contained value or computes a default result by `defFn`.
*/
mapOrElse(def, fn) {
if (this.ok) {
// This code is required to keep backward compatibility.
// @ts-expect-error
return fn(this.val);
}
else {
return def();
}
}
/**
* Returns `None` if the self is `None`, otherwise returns `optb`.
*/
and(optb) {
// This code is required to keep backward compatibility.
// @ts-expect-error
return this.ok ? optb : this;
}
/**
* The alias of `Option<T>.flatMap()`.
*/
andThen(fn) {
return this.flatMap(fn);
}
/**
* Returns the self if it contains a value, otherwise returns `optb`.
*
* @template T
*
* @param {!Option<T>} optb
* @return {!Option<T>}
*/
or(optb) {
// This code is required to keep backward compatibility.
// @ts-expect-error
return this.ok ? this : optb;
}
/**
* Returns the self if it contains a value,
* otherwise calls `fn` and returns the result.
*/
orElse(fn) {
if (this.ok) {
// This code is required to keep backward compatibility.
// @ts-expect-error
return this;
}
else {
const value = fn();
if (value instanceof ClassicOptionBase) {
return value;
}
throw new TypeError("Option<T>.orElse()' param `fn` should return `Option<T>`.");
}
}
/**
* Finalize the self.
* After this is called, the object's behavior is not defined.
*
* @param destructor
* This would be called with the inner value if self is `Some<T>`.
*/
drop(destructor) {
if (this.ok && typeof destructor === 'function') {
// This code is required to keep backward compatibility.
// @ts-expect-error
destructor(this.val);
}
// This code is required to keep backward compatibility.
// @ts-expect-error
this.val = null;
Object.freeze(this);
}
// FYI: this is json representation.
// eslint-disable-next-line @typescript-eslint/naming-convention
toJSON() {
return {
// eslint-disable-next-line @typescript-eslint/naming-convention
is_some: this.ok,
value: this.val,
};
}
}
Object.freeze(ClassicOptionBase.prototype);
/**
* @deprecated
* See https://github.com/option-t/option-t/issues/459
*/
export function createClassicSome(val) {
// This code is required to keep backward compatibility.
// @ts-expect-error
const o = new ClassicOptionBase(true, val);
return o;
}
/**
* @deprecated
* See https://github.com/option-t/option-t/issues/459
*/
export function createClassicNone() {
// This code is required to keep backward compatibility.
// @ts-expect-error
const o = new ClassicOptionBase(false, undefined);
return o;
}
/**
* @deprecated
* See https://github.com/option-t/option-t/issues/459
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
export const ClassicSomeConstructor = function ClassicSomeConstructor(val) {
return createClassicSome(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 ClassicNoneConstructor = function ClassicNoneConstructor() {
return createClassicNone();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
};