176 lines
2.9 KiB
JavaScript
176 lines
2.9 KiB
JavaScript
|
/**
|
||
|
* Rust-style optional type
|
||
|
*
|
||
|
* Based on https://gist.github.com/s-panferov/575da5a7131c285c0539
|
||
|
*/
|
||
|
export default interface Option<T> {
|
||
|
isSome(): boolean;
|
||
|
isNone(): boolean;
|
||
|
isSomeAnd(fn: (a: T) => boolean): boolean;
|
||
|
isNoneAnd(fn: () => boolean): boolean;
|
||
|
unwrap(): T | never;
|
||
|
unwrapOr(def: T): T;
|
||
|
unwrapOrElse(f: () => T): T;
|
||
|
map<U>(f: (a: T) => U): Option<U>;
|
||
|
mapOr<U>(def: U, f: (a: T) => U): U;
|
||
|
mapOrElse<U>(def: () => U, f: (a: T) => U): U;
|
||
|
and<U>(optb: Option<U>): Option<U>;
|
||
|
andThen<U>(f: (a: T) => Option<U>): Option<U>;
|
||
|
or(optb: Option<T>): Option<T>;
|
||
|
orElse(f: () => Option<T>): Option<T>;
|
||
|
}
|
||
|
|
||
|
class _Some<T> implements Option<T> {
|
||
|
private value: T;
|
||
|
|
||
|
constructor(v: T) {
|
||
|
this.value = v;
|
||
|
}
|
||
|
|
||
|
static wrapNull<T>(value: T): Option<T> {
|
||
|
if (value == null) {
|
||
|
return None;
|
||
|
} else {
|
||
|
return new _Some<T>(value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
map<U>(fn: (a: T) => U): Option<U> {
|
||
|
return new _Some(fn(this.value));
|
||
|
}
|
||
|
|
||
|
mapOr<U>(_def: U, f: (a: T) => U): U {
|
||
|
return f(this.value);
|
||
|
}
|
||
|
|
||
|
mapOrElse<U>(_def: () => U, f: (a: T) => U): U {
|
||
|
return f(this.value);
|
||
|
}
|
||
|
|
||
|
isSome(): boolean {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
isNone(): boolean {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
isSomeAnd(fn: (a: T) => boolean): boolean {
|
||
|
return fn(this.value);
|
||
|
}
|
||
|
|
||
|
isNoneAnd(_fn: () => boolean): boolean {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
unwrap(): T {
|
||
|
return this.value;
|
||
|
}
|
||
|
|
||
|
unwrapOr(_def: T): T {
|
||
|
return this.value;
|
||
|
}
|
||
|
|
||
|
unwrapOrElse(_f: () => T): T {
|
||
|
return this.value;
|
||
|
}
|
||
|
|
||
|
and<U>(optb: Option<U>): Option<U> {
|
||
|
return optb;
|
||
|
}
|
||
|
|
||
|
andThen<U>(f: (a: T) => Option<U>): Option<U> {
|
||
|
return f(this.value);
|
||
|
}
|
||
|
|
||
|
or(_optb: Option<T>): Option<T> {
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
orElse(_f: () => Option<T>): Option<T> {
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
toString(): string {
|
||
|
return 'Some ' + this.value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class _None<T> implements Option<T> {
|
||
|
constructor() {
|
||
|
}
|
||
|
|
||
|
map<U>(_fn: (a: T) => U): Option<U> {
|
||
|
return <Option<U>> _None._instance;
|
||
|
}
|
||
|
|
||
|
isSome(): boolean {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
isNone(): boolean {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
isSomeAnd(_fn: (a: T) => boolean): boolean {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
isNoneAnd(fn: () => boolean): boolean {
|
||
|
return fn();
|
||
|
}
|
||
|
|
||
|
unwrap(): never {
|
||
|
console.error('None.unwrap()');
|
||
|
throw 'None.get';
|
||
|
}
|
||
|
|
||
|
unwrapOr(def: T): T {
|
||
|
return def;
|
||
|
}
|
||
|
|
||
|
unwrapOrElse(f: () => T): T {
|
||
|
return f();
|
||
|
}
|
||
|
|
||
|
mapOr<U>(def: U, _f: (a: T) => U): U {
|
||
|
return def;
|
||
|
}
|
||
|
|
||
|
mapOrElse<U>(def: () => U, _f: (a: T) => U): U {
|
||
|
return def();
|
||
|
}
|
||
|
|
||
|
and<U>(_optb: Option<U>): Option<U> {
|
||
|
return _None.instance<U>();
|
||
|
}
|
||
|
|
||
|
andThen<U>(_f: (a: T) => Option<U>): Option<U> {
|
||
|
return _None.instance<U>();
|
||
|
}
|
||
|
|
||
|
or(optb: Option<T>): Option<T> {
|
||
|
return optb;
|
||
|
}
|
||
|
|
||
|
orElse(f: () => Option<T>): Option<T> {
|
||
|
return f();
|
||
|
}
|
||
|
|
||
|
private static _instance: Option<any> = new _None();
|
||
|
|
||
|
public static instance<X>(): Option<X> {
|
||
|
return <Option<X>> _None._instance;
|
||
|
}
|
||
|
|
||
|
public toString(): string {
|
||
|
return 'None';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export const None: Option<any> = _None.instance();
|
||
|
|
||
|
export function Some<T>(value: T): Option<T> {
|
||
|
return _Some.wrapNull(value);
|
||
|
}
|