import { OptionCombinators, ResultLike, ResultLikeShouldUseMapResult, ResultPromise, ResultPromiseLike, ResultPromiseShouldUseMapResult } from "./mod"; /** * Type `Option` represents an optional value: every Option is either `Some` and contains a value, * or `None`, and does not. * `Option` types are very common, as they have a number of uses: * * - Initial values * - Return values for functions that are not defined over their entire input range (partial functions) * - Return value for otherwise reporting simple errors, where `None` is returned on error * - Optional fields * - Optional function arguments * - Nullable pointers * - Swapping things out of difficult situations * * ### A note on (the lack of) unwrap/expect * * Rust has two methods that might panic: `unwrap` and `expect` * * ```rust * let body = document.body.unwrap(); * let title = body.get_attribute("title").expect("should have title attribute!"); * ``` * * Neither of these are implemented in this Javascript library. Use the combinator * methods to handle all possibilities: * * ```typescript * const title = document.body() * .map( body => body.getAttribute("title) ) * .unwrapOr("*** No title given ***"); * ``` * * @example * ```typescript * function divide(numerator: number, denominator: number): Option { * if (denominator === 0) { * return None(); * } else { * return Some(numerator / denominator); * } * } * * // The return value of the function is an option * const result = divide(2.0, 3.0); * * // Pattern match to retrieve the value * const message = result.mapOrElse( * () => "Cannot divide by 0", * (some) => `Result: ${some}`, * ); * * console.log(message); // "Result: 0.6666666666666666" * * // This can al be done using combinators * console.log( * Some(2.0 / 3.0) * .map((some) => `Result: ${some}`) * .unwrapOr("Cannot divide by 0"), * ); * ``` */ export interface Option extends OptionCombinators { /** * Inserts value into the option if it is None, then returns a mutable reference to the contained value. * * See also Option::insert, which updates the value even if the option already contains Some. * ```typescript * const x = None<{answer: number}>(); * const y = x.getOrInsert({ answer: 41}); * y.answer = 42; * assertEquals( x, Some({ answer: 42})); * ``` */ getOrInsert(value: T): T; /** * Inserts a value computed from f into the option if it is None, then returns a mutable reference to the contained value. */ getOrInsertWith(fn: () => T): T; /** * Inserts value into the option, then returns a mutable reference to it. * * If the option already contains a value, the old value is dropped. * * See also Option::getOrInsert, which doesn’t update the value if the option already contains Some. */ insert(value: T): T; /** * Replaces the actual value in the option by the value given in parameter, * returning the old value if present, leaving a Some in its place without deinitializing either one. * * @example * ```typescript * let mut x = Some(2); * let old = x.replace(5); * assert_eq!(x, Some(5)); * assert_eq!(old, Some(2)); * * let mut x = None; * let old = x.replace(3); * assert_eq!(x, Some(3)); * assert_eq!(old, None); * ``` */ replace(value: T): Option; /** * Takes the value out of the option, leaving a None in its place. */ take(): Option; } /** * `Option` has several combinator methods, like andThen, orElse * and map. Those methods accept one or more callback functions that can be async. * * The examples below demonstrates how Promises and async callbacks can be combined * with the andThen and mapOrElse. * * @example * ```typescript * function getAnswer() { * return Promise.resolve(42); * } * * Some(getAnswer()) * .map(async (answer) => await Promise.resolve(`${answer}`)) * .map((answerText) => `answer: ${answerText}`) * .map(console.log); * ``` */ export interface OptionPromise extends Promise> { /** * Returns None if the option is None, otherwise returns optb. * * Arguments passed to and are eagerly evaluated; if you are passing the result of a function call, * it is recommended to use {@linkcode andThen}, which is lazily evaluated. */ and(optb: Option): OptionPromise; /** * Returns None if the option is None, otherwise calls f with the wrapped value and returns the result. * * Some languages call this operation flatmap. */ andThen(fn: (some: T) => OptionPromise): OptionPromise; andThen(fn: (some: T) => Promise>): OptionPromise; andThen(fn: (some: T) => Option): OptionPromise; /** * Converts from Option> to Option. */ flatten(this: Option>): OptionPromise; flatten(this: Option): OptionPromise; /** * Returns None if the option is None, otherwise calls predicate with the wrapped value and returns: * * - Some(t) if predicate returns true (where t is the wrapped value), and * - None if predicate returns false. */ filter(predicate: (some: T) => boolean): OptionPromise; isSome(): Promise; isNone(): Promise; /** * Maps an Option to an Option by applying a function to a contained value. */ map(fn: (some: T) => U): OptionPromise; /** * Computes a default function result (if None), or applies a different function to the contained value (if Some). * * When U is `Promise>`, the actual return type will be `OptionPromise`. * U should not be `Promise

` where P is not Option, @see {@linkcode mapOrElse} or @see {@linkcode mapResult}for returning non-Option promises */ mapOption(def: () => U, fn: (some: T) => U): OptionPromiseMapOption; /** * Computes a default function result (if None), or applies a different function to the contained value (if Some). * * When U is `Promise>`, the actual return type will be `ResultPromise`. * U should not be `Promise

` where P is not Option, @see {@linkcode mapOrElse} or {@linkcode mapOption} for returning other promises */ mapResult(def: () => U, fn: (some: T) => U): OptionPromiseMapResult; /** * Computes a default function result (if None), or applies a different function to the contained value (if Some). * * When U is `Promise

`, the actual return type will be Promise

, otherwise the return type will be Promise. * * U should not be `Promise>` @see {@linkcode mapOption}, nor `Promise>`{@linkcode mapResult} for * returning promises to Option or Result */ mapOrElse(def: () => U, fn: (some: T) => U): OptionPromiseMapOrElse; /** * Transforms the {@linkcode Option} into a {@linkcode Result}, * mapping {@linkcode Some(v)} to {@linkcode Ok(v)} and {@linkcode None} to {@linkcode Err(err)}. * * Arguments passed to okOr are eagerly evaluated; if you are passing the result of a function call, * it is recommended to use {@linkcode okOrElse}, which is lazily evaluated. */ okOr(err: E): ResultPromise; /** * Transforms the {@linkcode Option} into a {@linkcode Result}, * mapping {@linkcode Some(v)} to {@linkcode Ok(v)} and {@linkcode None} to {@linkcode Err(fn())}. */ okOrElse(fn: () => Promise): ResultPromise; okOrElse(fn: () => E): ResultPromise; /** * Returns the option if it contains a value, otherwise returns optb. * * Arguments passed to or are eagerly evaluated; if you are passing the result of a function call, * it is recommended to use {@linkcode orElse}, which is lazily evaluated. */ or(optb: Option): OptionPromise; /** * Returns the option if it contains a value, otherwise calls f and returns the result. */ orElse(fn: () => Promise>): OptionPromise; orElse(fn: () => Option): OptionPromise; /** * Returns the contained Some value or a provided default. * * Arguments passed to unwrap_or are eagerly evaluated; * if you are passing the result of a function call, * it is recommended to use {@linkcode unwrapOrElse}, which is lazily evaluated. */ unwrapOr(def: T): Promise; /** * Returns the contained Some value or computes it from a closure. */ unwrapOrElse(def: () => T): Promise; unwrapOrElse(def: () => Promise): Promise; /** * Returns Some if exactly one of self, optb is Some, otherwise returns None. */ xor(optb: Option): OptionPromise; } export type OptionPromiseShouldUseMapOption = "To return a Promise to an Option, use mapOption"; export type OptionLikeShouldUseMapOption = "To return (a Promise to) an Option, use mapOption"; export type NoOptionPromiseShouldUseMapOrElse = "To return a promise to anything other than Option, use mapOrElse"; /** * Value is something that implements an interface with * the `OptionPromise` combinators e.g., `andThen`, `orElse`, `map` and `mapOrElse` * as well as the Promise

: U extends Option ? Option : Option; export type OptionFrom = U extends Promise> | OptionPromise ? OptionPromise : U extends Promise ? OptionPromise : U extends Option ? Option : Option; export type OptionMapOrElse = T extends OptionPromiseLike ? OptionPromiseShouldUseMapOption : T extends ResultPromiseLike ? ResultPromiseShouldUseMapResult : T; export type OptionPromiseMapOrElse = T extends OptionLike ? OptionLikeShouldUseMapOption : T extends ResultLike ? ResultLikeShouldUseMapResult : T extends Promise ? Promise

: Promise; export type OptionMapOption = T extends OptionPromiseLike ? OptionPromise : T extends ResultPromiseLike ? ResultPromiseShouldUseMapResult : T extends Promise ? OptionPromise

: T; export type OptionPromiseMapOption = T extends OptionLike ? OptionPromise : T extends ResultLike ? ResultLikeShouldUseMapResult : T extends Promise ? OptionPromise

: OptionPromise; export type OptionMapResult = T extends ResultPromiseLike ? ResultPromise : T extends OptionPromiseLike ? OptionPromiseShouldUseMapOption : T extends Promise ? ResultPromise : T; export type OptionPromiseMapResult = T extends ResultLike ? ResultPromise : T extends OptionLike ? OptionLikeShouldUseMapOption : T extends Promise ? ResultPromise : ResultPromise;