// @flow export interface Option<+T> { /* eslint-disable no-undef */ isDefined(): boolean; isEmpty(): boolean; get(): T; getOrElse(U): T | U; default(U): T | U; getOrNull(): T | null; getOrUndefined(): T | void; map((T) => U): Option; filter((T) => boolean): Option; reject((T) => boolean): Option; bind((T) => Option): Option; flatMap((T) => Option): Option; fold(U, (T) => U): U; foldLeft(U, (U, T) => U): U; foldRight(U, (T, U) => U): U; forEach((T) => void): void; /* eslint-enable */ } class None implements Option { isDefined(): boolean { return false; } isEmpty(): boolean { return true; } get() { throw new Error('NO VALUE'); } getOrElse(defaultValue: U): U { return defaultValue; } default(defaultValue: U): U { return this.getOrElse(defaultValue); } getOrNull(): null { return null; } getOrUndefined(): void { return undefined; } map(_m: (any) => U): None { return new None(); } filter(_p: (any) => boolean): None { return new None(); } reject(_p: (any) => boolean): None { return new None(); } bind(_m: (any) => Option): None { return new None(); } flatMap(m: (any) => Option): None { return this.bind(m); } fold(initialValue: U, f: (any) => U): U { return this.map(f).getOrElse(initialValue); } foldLeft(initialValue: U, _f: (U, any) => U): U { return initialValue; } foldRight(initialValue: U, _f: (any, U) => U): U { return initialValue; } forEach(_f: any): void {} } class Some implements Option { value: T; constructor(value: T) { this.value = value; } isDefined(): boolean { return true; } isEmpty(): boolean { return false; } get(): T { return this.value; } getOrElse(_defaultValue: U): T { return this.get(); } default(_defaultValue: U): T { return this.getOrElse(); } getOrNull(): T { return this.get(); } getOrUndefined(): T { return this.get(); } map(m: (T) => U): Some { return new Some(m(this.get())); } filter(p: (T) => boolean): Option { return p(this.get()) ? new Some(this.get()) : new None(); } reject(p: (T) => boolean): Option { return this.filter((x: T) => !p(x)); } bind(m: (T) => Option): Option { return m(this.get()); } flatMap(m: (T) => Option): Option { return this.bind(m); } fold(initialValue: U, f: (T) => U): U { return this.map(f).getOrElse(initialValue); } foldLeft(initialValue: U, f: (U, T) => U): U { return f(initialValue, this.get()); } foldRight(initialValue: U, f: (T, U) => U): U { return f(this.get(), initialValue); } forEach(f: (T) => void): void { f(this.get()); } } function none(): None { return new None(); } function some(value: T): Some { return new Some(value); } function option(value: ?T): Option { return value == null ? none() : some(value); } const Opt = { None, Some, none, some, option, }; export { None, Some, none, some, option, Opt as default };