utilitaire
Version:
Common utils for JavaScript and Typescript development
104 lines (84 loc) • 3.03 kB
text/typescript
/**
* The Option type encapsulates an optional value.
* A value of type Option<T> either :
* - contains a value of type T,
* - or it is empty (represented as None).
*
* Using Option is a good way to deal with null and undefined.
*/
export abstract class Option<T> {
protected _value: T;
/**
* Returns the option's value.
* @note The option must be nonEmpty and this will return
* undefined if the option is empty.
*/
get value () : T { return this._value; }
valueOrElse(value:T): T {
if(this.isDefined()) return this.value;
else return value;
}
valueOrNull(): T {
if(this.isDefined()) return this.value;
else return null;
}
isDefined(): boolean {
return this.value != undefined;
}
isEmpty() : boolean {
return !this.isDefined();
}
flatMap<U>(fn:(T) => Option<U>): Option<U> {
if(this.isEmpty()) return None;
else {
const resultOption = fn(this.value);
if(Option.isDefinedValue(resultOption)) return resultOption;
else return None;
}
}
map<U>(fn:(T) => U): Option<U> {
if(this.isDefined()) return Option.of(fn(this.value));
else return None;
}
forEach(fn:(T) => void) {
if(this.isDefined())
fn(this.value);
}
static isDefinedValue(value:any): boolean {
return (value != null && value != undefined);
}
static of<T>(value : T) : Option<T> {
// If the provided _value is null or undefined, we let the property
// _value undefined else we defining it!
if(Option.isDefinedValue(value)) return new Some(value);
else return None;
}
static empty<T>() : Option<T> {
return None;
}
}
export class Some<T> extends Option<T>{
constructor(_value:T) {
super();
if(_value == null || _value == undefined)
throw new Error(
"Some constructor expected non null an non undefined value. " +
_value + "given. " +
"If you are not sure whether your value is defined or not, please " +
"consider the static method Option.of<T>(value:T) that will " +
"deal with the null/undefined case properly."
);
this._value = _value;
}
}
class NoneT extends Option<typeof undefined> {}
/**
* Here we use the instance of {} as instance of None. Indeed, the '{}' can be
* viewed as an instance of Option because of the Option class definition.
* as we did not defined a '_value' attribute, every call to the isDefined() method
* will always yield false. It is then enough to have a correct working Option instance
* For example see the 'map', and 'foreach' method definition.
*
* @type {Option<typeof undefined>}
*/
export const None = new NoneT() as Option<typeof undefined>;