/**
* @since 1.0.0
*/
import type { Either } from "@fp-ts/core/Either"
import type { LazyArg } from "@fp-ts/core/Function"
import { constNull, constUndefined, dual } from "@fp-ts/core/Function"
import type { Kind, TypeLambda } from "@fp-ts/core/HKT"
import { structural } from "@fp-ts/core/internal/effect"
import * as either from "@fp-ts/core/internal/Either"
import * as option from "@fp-ts/core/internal/Option"
import * as N from "@fp-ts/core/Number"
import type { Predicate, Refinement } from "@fp-ts/core/Predicate"
import type * as alternative from "@fp-ts/core/typeclass/Alternative"
import * as applicative from "@fp-ts/core/typeclass/Applicative"
import * as chainable from "@fp-ts/core/typeclass/Chainable"
import type * as coproduct_ from "@fp-ts/core/typeclass/Coproduct"
import * as covariant from "@fp-ts/core/typeclass/Covariant"
import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence"
import * as equivalence from "@fp-ts/core/typeclass/Equivalence"
import * as filterable from "@fp-ts/core/typeclass/Filterable"
import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap"
import * as foldable from "@fp-ts/core/typeclass/Foldable"
import * as invariant from "@fp-ts/core/typeclass/Invariant"
import type * as monad from "@fp-ts/core/typeclass/Monad"
import type { Monoid } from "@fp-ts/core/typeclass/Monoid"
import * as monoid from "@fp-ts/core/typeclass/Monoid"
import * as of_ from "@fp-ts/core/typeclass/Of"
import type { Order } from "@fp-ts/core/typeclass/Order"
import * as order from "@fp-ts/core/typeclass/Order"
import type * as pointed from "@fp-ts/core/typeclass/Pointed"
import * as product_ from "@fp-ts/core/typeclass/Product"
import type * as semiAlternative from "@fp-ts/core/typeclass/SemiAlternative"
import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative"
import * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct"
import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup"
import * as semigroup from "@fp-ts/core/typeclass/Semigroup"
import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct"
import * as traversable from "@fp-ts/core/typeclass/Traversable"
// -------------------------------------------------------------------------------------
// models
// -------------------------------------------------------------------------------------
/**
* @category models
* @since 1.0.0
*/
export interface None {
readonly _tag: "None"
}
/**
* @category models
* @since 1.0.0
*/
export interface Some {
readonly _tag: "Some"
readonly value: A
}
/**
* @category models
* @since 1.0.0
*/
export type Option = None | Some
/**
* @category type lambdas
* @since 1.0.0
*/
export interface OptionTypeLambda extends TypeLambda {
readonly type: Option
}
// -------------------------------------------------------------------------------------
// constructors
// -------------------------------------------------------------------------------------
/**
* Creates a new `Option` that represents the absence of a value.
*
* This can be useful when working with optional values or to represent a computation that failed.
* It returns a new `Option` object that does not contain any value.
*
* @category constructors
* @since 1.0.0
*/
export const none = (): Option => option.none
/**
* Creates a new `Option` that wraps the given value.
*
* This can be useful when working with optional values or to represent a computation that succeeded with a value.
*
* @param value - The value to wrap.
*
* @category constructors
* @since 1.0.0
*/
export const some: (value: A) => Option = option.some
/**
* Alias of {@link some}.
*
* @category constructors
* @since 1.0.0
*/
export const of: (value: A) => Option = some
// -------------------------------------------------------------------------------------
// guards
// -------------------------------------------------------------------------------------
/**
* Tests if a value is a `Option`.
*
* @param input - The value to check.
*
* @example
* import { some, none, isOption } from '@fp-ts/core/Option'
*
* assert.deepStrictEqual(isOption(some(1)), true)
* assert.deepStrictEqual(isOption(none()), true)
* assert.deepStrictEqual(isOption({}), false)
*
* @category guards
* @since 1.0.0
*/
export const isOption = (input: unknown): input is Option =>
typeof input === "object" && input != null && structural in input && "_tag" in input &&
(input["_tag"] === "None" || input["_tag"] === "Some")
/**
* Determine if a `Option` is a `None`.
*
* @param self - The `Option` to check.
*
* @example
* import { some, none, isNone } from '@fp-ts/core/Option'
*
* assert.deepStrictEqual(isNone(some(1)), false)
* assert.deepStrictEqual(isNone(none()), true)
*
* @category guards
* @since 1.0.0
*/
export const isNone: (self: Option) => self is None = option.isNone
/**
* Determine if a `Option` is a `Some`.
*
* @param self - The `Option` to check.
*
* @example
* import { some, none, isSome } from '@fp-ts/core/Option'
*
* assert.deepStrictEqual(isSome(some(1)), true)
* assert.deepStrictEqual(isSome(none()), false)
*
* @category guards
* @since 1.0.0
*/
export const isSome: (self: Option) => self is Some = option.isSome
// -------------------------------------------------------------------------------------
// pattern matching
// -------------------------------------------------------------------------------------
/**
* Matches the given `Option` and returns either the provided `onNone` value or the result of the provided `onSome`
* function when passed the `Option`'s value.
*
* @param self - The `Option` to match
* @param onNone - The value to be returned if the `Option` is `None`
* @param onSome - The function to be called if the `Option` is `Some`, it will be passed the `Option`'s value and its result will be returned
*
* @example
* import { some, none, match } from '@fp-ts/core/Option'
* import { pipe } from '@fp-ts/core/Function'
*
* assert.deepStrictEqual(
* pipe(
* some(1),
* match(() => 'a none', a => `a some containing ${a}`)
* ),
* 'a some containing 1'
* )
*
* assert.deepStrictEqual(
* pipe(
* none(),
* match(() => 'a none', a => `a some containing ${a}`)
* ),
* 'a none'
* )
*
* @category pattern matching
* @since 1.0.0
*/
export const match: {
(onNone: LazyArg, onSome: (a: A) => C): (self: Option) => B | C
(self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C
} = dual(
3,
(self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C =>
isNone(self) ? onNone() : onSome(self.value)
)
// -------------------------------------------------------------------------------------
// conversions
// -------------------------------------------------------------------------------------
/**
* Returns a `Refinement` from a `Option` returning function.
* This function ensures that a `Refinement` definition is type-safe.
*
* @category conversions
* @since 1.0.0
*/
export const toRefinement = (f: (a: A) => Option): Refinement =>
(a: A): a is B => isSome(f(a))
/**
* Converts an `Iterable` of values into an `Option`. Returns the first value of the `Iterable` wrapped in a `Some`
* if the `Iterable` is not empty, otherwise returns `None`.
*
* @param collection - The `Iterable` to be converted to an `Option`.
*
* @example
* import { fromIterable, some, none } from '@fp-ts/core/Option'
*
* const collection = [1, 2, 3]
* assert.deepStrictEqual(fromIterable(collection), some(1))
* assert.deepStrictEqual(fromIterable([]), none())
*
* @category conversions
* @since 1.0.0
*/
export const fromIterable = (collection: Iterable): Option => {
for (const a of collection) {
return some(a)
}
return none()
}
/**
* Converts a `Either` to an `Option` discarding the error.
*
* @param self - The `Either` to convert to an `Option`.
*
* @example
* import * as O from '@fp-ts/core/Option'
* import * as E from '@fp-ts/core/Either'
*
* assert.deepStrictEqual(O.fromEither(E.right(1)), O.some(1))
* assert.deepStrictEqual(O.fromEither(E.left('a')), O.none())
*
* @category conversions
* @since 1.0.0
*/
export const fromEither: (self: Either) => Option = either.getRight
/**
* Converts a `Either` to an `Option` discarding the error.
*
* Alias of {@link fromEither}.
*
* @example
* import * as O from '@fp-ts/core/Option'
* import * as E from '@fp-ts/core/Either'
*
* assert.deepStrictEqual(O.getRight(E.right('ok')), O.some('ok'))
* assert.deepStrictEqual(O.getRight(E.left('err')), O.none())
*
* @category conversions
* @since 1.0.0
*/
export const getRight: (self: Either) => Option = fromEither
/**
* Converts a `Either` to an `Option` discarding the value.
*
* @example
* import * as O from '@fp-ts/core/Option'
* import * as E from '@fp-ts/core/Either'
*
* assert.deepStrictEqual(O.getLeft(E.right('ok')), O.none())
* assert.deepStrictEqual(O.getLeft(E.left('err')), O.some('err'))
*
* @category conversions
* @since 1.0.0
*/
export const getLeft: (self: Either) => Option = either.getLeft
/**
* Converts an `Option` to an `Either`, allowing you to provide a value to be used in the case of a `None`.
*
* @param self - the `Option` to convert.
* @param onNone - a function that produces an error value when the `Option` is `None`.
*
* @example
* import { pipe } from '@fp-ts/core/Function'
* import * as O from '@fp-ts/core/Option'
* import * as E from '@fp-ts/core/Either'
*
* const onNone = () => 'error'
* assert.deepStrictEqual(pipe(O.some(1), O.toEither(onNone)), E.right(1))
* assert.deepStrictEqual(pipe(O.none(), O.toEither(onNone)), E.left('error'))
*
* @category conversions
* @since 1.0.0
*/
export const toEither: {
(self: Option, onNone: () => E): Either
(onNone: () => E): (self: Option) => Either
} = either.fromOption
// -------------------------------------------------------------------------------------
// error handling
// -------------------------------------------------------------------------------------
/**
* Returns the value of the `Option` if it is `Some`, otherwise returns `onNone`
*
* @param self - The `Option` to get the value of.
* @param onNone - Function that returns the default value to return if the `Option` is `None`.
*
* @example
* import { some, none, getOrElse } from '@fp-ts/core/Option'
* import { pipe } from '@fp-ts/core/Function'
*
* assert.deepStrictEqual(pipe(some(1), getOrElse(() => 0)), 1)
* assert.deepStrictEqual(pipe(none(), getOrElse(() => 0)), 0)
*
* @category error handling
* @since 1.0.0
*/
export const getOrElse: {
(onNone: LazyArg): (self: Option) => B | A
(self: Option, onNone: LazyArg): A | B
} = dual(
2,
(self: Option, onNone: LazyArg): A | B => isNone(self) ? onNone() : self.value
)
/**
* Returns the provided `Option` `that` if `self` is `None`, otherwise returns `self`.
*
* @param self - The first `Option` to be checked.
* @param that - The `Option` to return if `self` is `None`.
*
* @example
* import * as O from '@fp-ts/core/Option'
* import { pipe } from '@fp-ts/core/Function'
*
* assert.deepStrictEqual(
* pipe(
* O.none(),
* O.orElse(() => O.none())
* ),
* O.none()
* )
* assert.deepStrictEqual(
* pipe(
* O.some('a'),
* O.orElse(() => O.none())
* ),
* O.some('a')
* )
* assert.deepStrictEqual(
* pipe(
* O.none(),
* O.orElse(() => O.some('b'))
* ),
* O.some('b')
* )
* assert.deepStrictEqual(
* pipe(
* O.some('a'),
* O.orElse(() => O.some('b'))
* ),
* O.some('a')
* )
*
* @category error handling
* @since 1.0.0
*/
export const orElse: {
(that: LazyArg