/**
 * Created by Bruno Grieder.
 */ import { Collection } from './Collection' ; export class Option < A > extends Collection < A > { static from < A > ( optVal ) { if ( typeof optVal [ Symbol . iterator ] === 'undefined' ) { return new Option < A > ( [ optVal ] ) ; } return new Option < A > ( optVal ) ; } /**
     * Returns a Some containing the result of applying pf to this Option's contained value, if this option is nonempty and pf is defined for that value.
     */ collect < B > ( filter ) { return ( mapper ) => super . collect ( filter ) ( mapper ) as Option < B > ; } /**
     * Tests whether the value of the Option pass the filter, and applies the partial function to it.
     */ collectFirst < B > ( filter ) { return ( mapper ) => { return this . filter ( filter ) . map ( mapper ) as Option < B > ; } ; } /**
     * Returns true if this option is nonempty and the predicate p returns true when applied to this Option's value.
     */ exists ( p ) { return super . exists ( p ) ; } /**
     * Returns this Option if it is nonempty and applying the predicate p to this Option's value returns true.
     */ filter ( f ) { return super . filter ( f ) as Option < A > ; } /**
     * Returns this Option if it is nonempty and applying the predicate p to this Option's value returns false.
     */ filterNot ( f ) { return super . filterNot ( f ) as Option < A > ; } /**
     * Finds the first element of the iterable collection satisfying a predicate, if any.
     */ find ( p ) { return this . filter ( p ) as Option < A > ; } /**
     * Returns the result of applying f to this Option's value if this Option is nonempty.
     */ flatMap < U > ( f ) { return super . flatMap ( f ) as Option < U > ; } /**
     * Converts this Option of Option into an Option
     * e.g. some( some(1) ).flatten() -> some(1)
     */ flatten < U > ( ) { return super . flatten < U > ( ) as Option < U > ; } /**
     * Returns true if this option is empty or the predicate p returns true when applied to this Option's value.
     */ forall ( p ) { return super . forall ( p ) ; } /**
     * Apply the given procedure f to the option's value, if it is nonempty.
     */ foreach ( f ) { return super . foreach ( f ) ; } get get ( ) : A { return this . head ; } /**
     * Returns the option's value if the option is nonempty, otherwise return the result of evaluating default.
     */ getOrElse < U > ( elseVal ) { try { return this . get ; } catch ( e ) { return elseVal ( ) ; } } /**
     * Optionally selects the first element.
     */ get headOption ( ) : Option < A > { return new Option < A > ( this ) ; } /**
     * Returns true if the option is an instance of Some, false otherwise.
     */ get isDefined ( ) : boolean { return ! this . isEmpty ; } /**
     * Selects the last element.
     */ get last ( ) : A { if ( this . isEmpty ) { throw new Error ( "No such element: last in None" ) ; } return this . get ; } /**
     * Optionally selects the last element.
     */ get lastOption ( ) : Option < A > { return new Option < A > ( this ) ; } /**
     * Returns a Some containing the result of applying f to this Option's value if this Option is nonempty.
     */ map < U > ( f ) { return super . map < U > ( f ) as Option < U > ; } /**
     * Returns false if the option is None, true otherwise.
     */ get nonEmpty ( ) : boolean { return ! this . isEmpty ; } /**
     * Returns this Option if it is nonempty, otherwise return the result of evaluating alternative.
     */ orElse ( alternative ) { return this . isEmpty ? alternative ( ) : this ; } /**
     * Returns the option's value if it is nonempty, or null if it is empty.
     */ get orNull ( ) : A { try { return this . get ; } catch ( e ) { return null ; } } /**
     * Returns the option's value if it is nonempty, or throws an error with the specified message
     */ orThrow ( message ) { try { return this . get ; } catch ( e ) { throw new Error ( message ( ) ) ; } } /**
     * Returns the option's value if it is nonempty, or undefined if it is empty.
     */ get orUndefined ( ) : A { try { return this . get ; } catch ( e ) { return void 0 ; } } /**
     * Converts this Option to a Promise, resolving it if it is a Some, rejecting it otherwise
     */ get toPromise ( ) : Promise < A > { return this . map ( v => Promise . resolve ( v ) ) . getOrElse ( ( ) => Promise . reject ( new Error ( 'No such element None.get' ) ) ) ; } } export function some < A > ( value ) { return Option . from < A > ( [ value ] ) ; } export function none ( ) { return Option . from < any > ( [ ] ) ; } /**
 * Create a None if value is undefined or null or NaN
 * otherwise create a Some holding that value
 */ export function option < A > ( value ) { return ( typeof value === 'undefined' || value === null || value !== value ) ? Option . from < A > ( [ ] ) : Option . from < A > ( value ) ; }