# Option

`Option<A>` models a value that may be absent. It is either `Some<A>`, holding a
value of type `A`, or `None`, representing no value. Use it instead of
`null`/`undefined` when absence is a normal, expected outcome — looking up a key,
parsing input, reading an optional field. The type then makes the missing case
visible and the compiler forces you to handle it.

```ts
import { Option } from "effect"

// A partial function: defined only for non-empty arrays
const head = <A>(array: ReadonlyArray<A>): Option.Option<A> =>
  array.length > 0 ? Option.some(array[0]) : Option.none()

// Handle both cases explicitly — no `undefined` checks leaking downstream
const describe = <A>(array: ReadonlyArray<A>): string =>
  Option.match(head(array), {
    onNone: () => "the array is empty",
    onSome: (value) => `the first element is ${value}`
  })

console.log(describe([1, 2, 3])) // "the first element is 1"
console.log(describe([]))        // "the array is empty"
```

`head` returns an `Option` rather than `A | undefined`, so every caller must
decide what to do when the value is missing. `Option.match` is the safe way to
do that: it takes one callback per case and returns a single value.

## Creating an Option

```ts
import { Option } from "effect"

const value = Option.some(1) // { _id: 'Option', _tag: 'Some', value: 1 }
const empty = Option.none()  // { _id: 'Option', _tag: 'None' }
```

`Option.none()` is a function call (not a constant) so it can infer the element
type at the use site.

To build an `Option` from a predicate, use `Option.liftPredicate`:

```ts
import { Option } from "effect"

//      ┌─── (n: number) => Option<number>
//      ▼
const parsePositive = Option.liftPredicate((n: number) => n > 0)

console.log(parsePositive(10)) // { _id: 'Option', _tag: 'Some', value: 10 }
console.log(parsePositive(-1)) // { _id: 'Option', _tag: 'None' }
```

## Modeling optional fields

Use `Option<A>` for properties that may have no value. The key is always
present; only the *value* is optional, which is exactly what `Option` expresses.

```ts
import { Option } from "effect"

interface User {
  readonly id: number
  readonly username: string
  // The `email` key is always present; the value may be absent
  readonly email: Option.Option<string>
}

const withEmail: User = {
  id: 1,
  username: "john_doe",
  email: Option.some("john.doe@example.com")
}

const withoutEmail: User = {
  id: 2,
  username: "jane_doe",
  email: Option.none()
}
```

## Transforming and chaining

`Option.map` transforms the value inside a `Some` and leaves a `None` untouched.
`Option.flatMap` is for functions that *themselves* return an `Option`, letting
you walk nested optional data without manual checks.

```ts
import { Option } from "effect"

interface Address {
  readonly city: string
  readonly street: Option.Option<string>
}
interface User {
  readonly address: Option.Option<Address>
}

const user: User = {
  address: Option.some({
    city: "New York",
    street: Option.some("123 Main St")
  })
}

// If `address` is None, the chain short-circuits to None.
// Otherwise we dig into the nested optional `street`.
const street = user.address.pipe(
  Option.flatMap((address) => address.street)
)

console.log(street) // { _id: 'Option', _tag: 'Some', value: '123 Main St' }
```

`Option.filter` keeps the value only if a predicate holds, turning it into
`None` otherwise:

```ts
import { Option } from "effect"

// Treat an empty string as "no value"
const nonEmpty = (input: Option.Option<string>) =>
  Option.filter(input, (value) => value !== "")

console.log(nonEmpty(Option.some(""))) // { _id: 'Option', _tag: 'None' }
console.log(nonEmpty(Option.some("a"))) // { _id: 'Option', _tag: 'Some', value: 'a' }
```

## Extracting the value

To get a plain value back out, supply a fallback so the `None` case is always
handled:

```ts
import { Option } from "effect"

// Provide a default for the None case
console.log(Option.getOrElse(Option.some(5), () => 0)) // 5
console.log(Option.getOrElse(Option.none(), () => 0))  // 0

// Interop with code that expects null / undefined
console.log(Option.getOrNull(Option.none()))      // null
console.log(Option.getOrUndefined(Option.some(5))) // 5

// Throws if None — use only at boundaries where None is truly impossible
console.log(Option.getOrThrow(Option.some(10))) // 10
```

## Fallbacks

`Option.orElse` tries an alternative when the first `Option` is `None`, and
`Option.firstSomeOf` returns the first `Some` from a list:

```ts
import { Option } from "effect"

const fromCache = Option.none<number>()
const fromDb = Option.some(42)

console.log(Option.orElse(fromCache, () => fromDb))
// { _id: 'Option', _tag: 'Some', value: 42 }

console.log(
  Option.firstSomeOf([Option.none(), Option.some(2), Option.some(3)])
)
// { _id: 'Option', _tag: 'Some', value: 2 }
```

## Interop with nullable values

`Option.fromNullishOr` converts `null`/`undefined` into `None`, and any other
value into `Some`. It is the bridge between Effect code and APIs that return
nullable values.

```ts
import { Option } from "effect"

console.log(Option.fromNullishOr(null))      // { _id: 'Option', _tag: 'None' }
console.log(Option.fromNullishOr(undefined)) // { _id: 'Option', _tag: 'None' }
console.log(Option.fromNullishOr(1))         // { _id: 'Option', _tag: 'Some', value: 1 }
```

Going the other way, `Option.getOrNull` / `Option.getOrUndefined` turn a `None`
back into `null` / `undefined`.

## Combining multiple Options

`Option.all` combines several `Option`s into one, preserving the input shape
(tuple, struct, or iterable). If any input is `None`, the result is `None`.

```ts
import { Option } from "effect"

const maybeName: Option.Option<string> = Option.some("John")
const maybeAge: Option.Option<number> = Option.some(25)

//      ┌─── Option<{ name: string; age: number }>
//      ▼
const struct = Option.all({ name: maybeName, age: maybeAge })
console.log(struct)
// { _id: 'Option', _tag: 'Some', value: { name: 'John', age: 25 } }

// One None makes the whole thing None
console.log(Option.all([Option.some("John"), Option.none()]))
// { _id: 'Option', _tag: 'None' }
```

To combine two values with a function, use `Option.zipWith`.

## Generator syntax

Like `Effect.gen`, `Option.gen` lets you write sequential code that
short-circuits on the first `None`. Each `yield*` either unwraps a `Some` or
aborts the whole block.

```ts
import { Option } from "effect"

const maybeName = Option.some("John")
const maybeAge = Option.some(25)

const person = Option.gen(function* () {
  const name = (yield* maybeName).toUpperCase()
  const age = yield* maybeAge
  return { name, age }
})

console.log(person)
// { _id: 'Option', _tag: 'Some', value: { name: 'JOHN', age: 25 } }
```

If `maybeName` were `None`, the generator would stop immediately and return
`None` — `age` would never be read. Keep these generators pure: `Option` is a
data structure, not an effect, so avoid side effects inside them.

## Interop with Effect

An `Option` can be used directly inside `Effect.gen`. A `Some<A>` yields its
value; a `None` fails the effect with a `NoSuchElementError`, which you can then
handle with the usual [Error Management](https://effect.plants.sh/error-management/) combinators.

```ts
import { Effect, Option } from "effect"

const program = Effect.gen(function* () {
  // `yield*` on a Some produces the value;
  // a None would fail with NoSuchElementError
  const x = yield* Option.some(10)
  const y = yield* Option.some(5)
  return x + y
})

Effect.runPromise(program).then(console.log) // 15
```

This makes `Option` a convenient way to express "may be missing" steps inside an
otherwise effectful workflow.

## API reference

Most combinators are *dual*: they accept either data-first
(`Option.map(self, f)`) or data-last (`self.pipe(Option.map(f))`) call styles.
The examples below mix both. Items that return a `Result` cross-reference the
[Result](https://effect.plants.sh/data-types/result/) data type.

### Constructors & guards

#### `some`

Wraps a present value in `Some`. Does not filter `null`/`undefined`.

```ts
import { Option } from "effect"

console.log(Option.some(1))
// => { _id: 'Option', _tag: 'Some', value: 1 }
```

#### `none`

Creates the absent `None`. It is a function call so the value type infers at the
use site (e.g. `Option.none<number>()`).

```ts
import { Option } from "effect"

console.log(Option.none<number>())
// => { _id: 'Option', _tag: 'None' }
```

#### `isOption`

Type guard for any `Option` (either `Some` or `None`), useful at runtime
boundaries.

```ts
import { Option } from "effect"

console.log(Option.isOption(Option.some(1))) // => true
console.log(Option.isOption({}))             // => false
```

#### `isSome`

Type guard narrowing an `Option<A>` to `Some<A>` so you can read `.value`.

```ts
import { Option } from "effect"

const o = Option.some(1)
console.log(Option.isSome(o) ? o.value : "absent") // => 1
```

#### `isNone`

Type guard narrowing an `Option<A>` to `None<A>`.

```ts
import { Option } from "effect"

console.log(Option.isNone(Option.none())) // => true
console.log(Option.isNone(Option.some(1))) // => false
```

### Pattern matching & refinement

#### `match`

Handles both branches in one expression, returning a plain value.

```ts
import { Option } from "effect"

console.log(
  Option.match(Option.some(1), {
    onNone: () => "empty",
    onSome: (value) => `value: ${value}`
  })
)
// => "value: 1"
```

#### `toRefinement`

Turns an `Option`-returning function into a type guard (returns `true` when the
function yields `Some`). Useful for `Array.prototype.filter`.

```ts
import { Option } from "effect"

const parseString = (x: string | number): Option.Option<string> =>
  typeof x === "string" ? Option.some(x) : Option.none()

const isString = Option.toRefinement(parseString)
console.log(isString("a")) // => true
console.log(isString(1))   // => false
```

#### `liftPredicate`

Converts a `Predicate` (or `Refinement`) into an `Option`-returning function:
`Some(value)` when it holds, `None` otherwise.

```ts
import { Option } from "effect"

const positive = Option.liftPredicate((n: number) => n > 0)
console.log(positive(1))  // => { _id: 'Option', _tag: 'Some', value: 1 }
console.log(positive(-1)) // => { _id: 'Option', _tag: 'None' }
```

### From other types

#### `fromIterable`

Wraps the first element of an iterable in `Some`, or `None` when empty. Only the
first element is consumed.

```ts
import { Option } from "effect"

console.log(Option.fromIterable([1, 2, 3])) // => { _id: 'Option', _tag: 'Some', value: 1 }
console.log(Option.fromIterable([]))        // => { _id: 'Option', _tag: 'None' }
```

#### `fromNullishOr`

Treats both `null` and `undefined` as `None`; any other value becomes
`Some` (typed `NonNullable<A>`).

```ts
import { Option } from "effect"

console.log(Option.fromNullishOr(null))      // => { _id: 'Option', _tag: 'None' }
console.log(Option.fromNullishOr(undefined)) // => { _id: 'Option', _tag: 'None' }
console.log(Option.fromNullishOr(1))         // => { _id: 'Option', _tag: 'Some', value: 1 }
```

#### `fromUndefinedOr`

Treats only `undefined` as `None`, leaving `null` as a valid `Some`.

```ts
import { Option } from "effect"

console.log(Option.fromUndefinedOr(undefined)) // => { _id: 'Option', _tag: 'None' }
console.log(Option.fromUndefinedOr(null))      // => { _id: 'Option', _tag: 'Some', value: null }
```

#### `fromNullOr`

Treats only `null` as `None`, leaving `undefined` as a valid `Some`.

```ts
import { Option } from "effect"

console.log(Option.fromNullOr(null))      // => { _id: 'Option', _tag: 'None' }
console.log(Option.fromNullOr(undefined)) // => { _id: 'Option', _tag: 'Some', value: undefined }
```

#### `liftNullishOr`

Lifts a function that may return `null`/`undefined` into one returning `Option`
(wraps the result via `fromNullishOr`).

```ts
import { Option } from "effect"

const parse = (s: string): number | undefined => {
  const n = parseFloat(s)
  return isNaN(n) ? undefined : n
}
const parseOption = Option.liftNullishOr(parse)
console.log(parseOption("1"))   // => { _id: 'Option', _tag: 'Some', value: 1 }
console.log(parseOption("nope")) // => { _id: 'Option', _tag: 'None' }
```

#### `liftThrowable`

Lifts a function that may throw into one returning `Option`: normal return →
`Some`, thrown exception → `None`.

```ts
import { Option } from "effect"

const parse = Option.liftThrowable(JSON.parse)
console.log(parse("1")) // => { _id: 'Option', _tag: 'Some', value: 1 }
console.log(parse(""))  // => { _id: 'Option', _tag: 'None' }
```

#### `getSuccess`

Converts a [`Result`](https://effect.plants.sh/data-types/result/) to an `Option`, keeping the success
value and discarding the failure.

```ts
import { Option, Result } from "effect"

console.log(Option.getSuccess(Result.succeed("ok"))) // => { _id: 'Option', _tag: 'Some', value: 'ok' }
console.log(Option.getSuccess(Result.fail("err")))   // => { _id: 'Option', _tag: 'None' }
```

#### `getFailure`

Converts a [`Result`](https://effect.plants.sh/data-types/result/) to an `Option`, keeping the failure
value and discarding the success.

```ts
import { Option, Result } from "effect"

console.log(Option.getFailure(Result.fail("err")))   // => { _id: 'Option', _tag: 'Some', value: 'err' }
console.log(Option.getFailure(Result.succeed("ok"))) // => { _id: 'Option', _tag: 'None' }
```

### Unwrapping & extraction

#### `getOrElse`

Returns the `Some` value, or lazily evaluates a fallback thunk on `None`.

```ts
import { Option } from "effect"

console.log(Option.getOrElse(Option.some(1), () => 0)) // => 1
console.log(Option.getOrElse(Option.none(), () => 0))  // => 0
```

#### `getOrNull`

Returns the `Some` value, or `null` on `None`.

```ts
import { Option } from "effect"

console.log(Option.getOrNull(Option.some(1))) // => 1
console.log(Option.getOrNull(Option.none()))  // => null
```

#### `getOrUndefined`

Returns the `Some` value, or `undefined` on `None`.

```ts
import { Option } from "effect"

console.log(Option.getOrUndefined(Option.some(1))) // => 1
console.log(Option.getOrUndefined(Option.none()))  // => undefined
```

#### `getOrThrow`

Returns the `Some` value, or throws a generic `Error` on `None`.

```ts
import { Option } from "effect"

console.log(Option.getOrThrow(Option.some(1))) // => 1
// Option.getOrThrow(Option.none())
// => throws Error: getOrThrow called on a None
```

#### `getOrThrowWith`

Returns the `Some` value, or throws the value produced by `onNone()` on `None`.

```ts
import { Option } from "effect"

console.log(Option.getOrThrowWith(Option.some(1), () => new Error("missing"))) // => 1
// Option.getOrThrowWith(Option.none(), () => new Error("missing"))
// => throws Error: missing
```

### Fallbacks

#### `orElse`

Returns `self` if `Some`; otherwise lazily evaluates the fallback `Option`.

```ts
import { Option } from "effect"

console.log(Option.orElse(Option.none(), () => Option.some("b"))) // => { _id: 'Option', _tag: 'Some', value: 'b' }
console.log(Option.orElse(Option.some("a"), () => Option.some("b"))) // => { _id: 'Option', _tag: 'Some', value: 'a' }
```

#### `orElseSome`

Like `orElse`, but the fallback is a plain value that is automatically wrapped
in `Some`.

```ts
import { Option } from "effect"

console.log(Option.orElseSome(Option.none(), () => "b")) // => { _id: 'Option', _tag: 'Some', value: 'b' }
```

#### `orElseResult`

Returns the first available value wrapped in a [`Result`](https://effect.plants.sh/data-types/result/) so
you can tell whether it came from the primary (`Failure`) or fallback
(`Success`).

```ts
import { Option } from "effect"

console.log(Option.orElseResult(Option.some("primary"), () => Option.some("fallback")))
// => { _id: 'Option', _tag: 'Some', value: { _id: 'Result', _tag: 'Failure', failure: 'primary' } }
console.log(Option.orElseResult(Option.none(), () => Option.some("fallback")))
// => { _id: 'Option', _tag: 'Some', value: { _id: 'Result', _tag: 'Success', success: 'fallback' } }
```

#### `firstSomeOf`

Returns the first `Some` in an iterable of `Option`s, or `None` if all are
`None`. Short-circuits on the first `Some`.

```ts
import { Option } from "effect"

console.log(Option.firstSomeOf([Option.none(), Option.some(1), Option.some(2)]))
// => { _id: 'Option', _tag: 'Some', value: 1 }
```

### Transforming & sequencing

#### `map`

Transforms the value inside a `Some`, leaving `None` unchanged.

```ts
import { Option } from "effect"

console.log(Option.map(Option.some(2), (n) => n * 2)) // => { _id: 'Option', _tag: 'Some', value: 4 }
console.log(Option.map(Option.none<number>(), (n) => n * 2)) // => { _id: 'Option', _tag: 'None' }
```

#### `as`

Replaces the `Some` value with a constant, preserving presence/absence.

```ts
import { Option } from "effect"

console.log(Option.as(Option.some(42), "x")) // => { _id: 'Option', _tag: 'Some', value: 'x' }
```

#### `asVoid`

Replaces the `Some` value with `undefined` (`Option<void>`).

```ts
import { Option } from "effect"

console.log(Option.asVoid(Option.some(42))) // => { _id: 'Option', _tag: 'Some', value: undefined }
```

`Option.void` is a pre-built `Some(undefined)` constant for the same purpose.

#### `flatMap`

Applies a function returning an `Option` and flattens the result; `None` skips
the function.

```ts
import { Option } from "effect"

console.log(Option.flatMap(Option.some(2), (n) => Option.some(n * 2)))
// => { _id: 'Option', _tag: 'Some', value: 4 }
console.log(Option.flatMap(Option.none<number>(), (n) => Option.some(n)))
// => { _id: 'Option', _tag: 'None' }
```

#### `andThen`

Flexible chaining: the next step can be a plain value, an `Option`, or a
function returning either. Plain values are wrapped in `Some`.

```ts
import { Option } from "effect"

console.log(Option.andThen(Option.some(5), (x) => Option.some(x * 2))) // => { _id: 'Option', _tag: 'Some', value: 10 }
console.log(Option.andThen(Option.some(5), "hello")) // => { _id: 'Option', _tag: 'Some', value: 'hello' }
```

#### `flatMapNullishOr`

`flatMap` combined with `fromNullishOr`: chains a function that may return
`null`/`undefined` (great for optional-chaining property access).

```ts
import { Option } from "effect"

interface Employee { company?: { address?: { street?: { name?: string } } } }
const emp: Employee = { company: { address: { street: { name: "high st" } } } }

console.log(
  Option.flatMapNullishOr(Option.some(emp), (e) => e.company?.address?.street?.name)
)
// => { _id: 'Option', _tag: 'Some', value: 'high st' }
```

#### `flatten`

Removes one layer of nesting from `Option<Option<A>>`.

```ts
import { Option } from "effect"

console.log(Option.flatten(Option.some(Option.some("v")))) // => { _id: 'Option', _tag: 'Some', value: 'v' }
console.log(Option.flatten(Option.some(Option.none())))    // => { _id: 'Option', _tag: 'None' }
```

#### `zipRight`

Sequences two `Option`s, keeping the second value when both are `Some`.

```ts
import { Option } from "effect"

console.log(Option.zipRight(Option.some(1), Option.some("hello"))) // => { _id: 'Option', _tag: 'Some', value: 'hello' }
console.log(Option.zipRight(Option.none(), Option.some("hello")))  // => { _id: 'Option', _tag: 'None' }
```

#### `zipLeft`

Sequences two `Option`s, keeping the first value when both are `Some`.

```ts
import { Option } from "effect"

console.log(Option.zipLeft(Option.some("hello"), Option.some(1)))   // => { _id: 'Option', _tag: 'Some', value: 'hello' }
console.log(Option.zipLeft(Option.some("hello"), Option.none()))    // => { _id: 'Option', _tag: 'None' }
```

#### `composeK`

Kleisli composition: combines two `Option`-returning functions into one,
short-circuiting on the first `None`.

```ts
import { Option } from "effect"

const parse = (s: string) => (isNaN(Number(s)) ? Option.none() : Option.some(Number(s)))
const double = (n: number) => (n > 0 ? Option.some(n * 2) : Option.none())
const parseAndDouble = Option.composeK(parse, double)

console.log(parseAndDouble("42"))  // => { _id: 'Option', _tag: 'Some', value: 84 }
console.log(parseAndDouble("nope")) // => { _id: 'Option', _tag: 'None' }
```

#### `tap`

Runs a side-condition `Option`-returning function; keeps the original value if
it returns `Some`, otherwise becomes `None`.

```ts
import { Option } from "effect"

const getInteger = (n: number) => (Number.isInteger(n) ? Option.some(n) : Option.none())

console.log(Option.tap(Option.some(1), getInteger))    // => { _id: 'Option', _tag: 'Some', value: 1 }
console.log(Option.tap(Option.some(1.5), getInteger))  // => { _id: 'Option', _tag: 'None' }
```

#### `filter`

Keeps the value only when a predicate (or refinement) holds; otherwise `None`.

```ts
import { Option } from "effect"

console.log(Option.filter(Option.some("hello"), (s) => s !== "")) // => { _id: 'Option', _tag: 'Some', value: 'hello' }
console.log(Option.filter(Option.some(""), (s) => s !== ""))      // => { _id: 'Option', _tag: 'None' }
```

#### `filterMap`

Transforms and filters at once via a [`Filter`](https://effect.plants.sh/data-types/result/) callback
that returns a `Result`: `Result.succeed` keeps the mapped value, `Result.fail`
discards it.

```ts
import { Option, Result } from "effect"

console.log(
  Option.filterMap(Option.some(2), (n) =>
    n % 2 === 0 ? Result.succeed(`Even: ${n}`) : Result.failVoid
  )
)
// => { _id: 'Option', _tag: 'Some', value: 'Even: 2' }
```

#### `partitionMap`

Splits a `Some` into a `[left, right]` pair using a function returning a
[`Result`](https://effect.plants.sh/data-types/result/): a `Failure` goes left, a `Success` goes right.

```ts
import { Option, Result } from "effect"

const parse = (s: string) =>
  isNaN(Number(s)) ? Result.fail("not a number") : Result.succeed(Number(s))

console.log(Option.partitionMap(Option.some("42"), parse))
// => [ { _id: 'Option', _tag: 'None' }, { _id: 'Option', _tag: 'Some', value: 42 } ]
console.log(Option.partitionMap(Option.some("abc"), parse))
// => [ { _id: 'Option', _tag: 'Some', value: 'not a number' }, { _id: 'Option', _tag: 'None' } ]
```

#### `reduceCompact`

Folds an iterable of `Option`s into a single value, skipping every `None`.

```ts
import { Option, pipe } from "effect"

const items = [Option.some(1), Option.none(), Option.some(2)]
console.log(pipe(items, Option.reduceCompact(0, (b, a) => b + a))) // => 3
```

#### `toArray`

Converts an `Option` to an array: `[value]` for `Some`, `[]` for `None`.

```ts
import { Option } from "effect"

console.log(Option.toArray(Option.some(1))) // => [ 1 ]
console.log(Option.toArray(Option.none()))  // => []
```

### Combining

#### `product`

Combines exactly two `Option`s into `Some([a, b])` when both are present.

```ts
import { Option } from "effect"

console.log(Option.product(Option.some("hello"), Option.some(42)))
// => { _id: 'Option', _tag: 'Some', value: [ 'hello', 42 ] }
console.log(Option.product(Option.none(), Option.some(42)))
// => { _id: 'Option', _tag: 'None' }
```

#### `productMany`

Combines a primary `Option` with an iterable of same-typed `Option`s into a
non-empty tuple; any `None` yields `None`.

```ts
import { Option } from "effect"

console.log(Option.productMany(Option.some(1), [Option.some(2), Option.some(3)]))
// => { _id: 'Option', _tag: 'Some', value: [ 1, 2, 3 ] }
```

#### `all`

Combines a tuple, struct, or iterable of `Option`s, preserving the input shape.
Any `None` makes the whole result `None`.

```ts
import { Option } from "effect"

console.log(Option.all([Option.some("John"), Option.some(25)]))
// => { _id: 'Option', _tag: 'Some', value: [ 'John', 25 ] }
console.log(Option.all({ name: Option.some("John"), age: Option.some(25) }))
// => { _id: 'Option', _tag: 'Some', value: { name: 'John', age: 25 } }
```

#### `zipWith`

Combines two `Option`s using a function; `None` if either is absent.

```ts
import { Option } from "effect"

console.log(Option.zipWith(Option.some(2), Option.some(3), (a, b) => a + b))
// => { _id: 'Option', _tag: 'Some', value: 5 }
```

#### `lift2`

Lifts a binary function so it operates on two `Option`s.

```ts
import { Option } from "effect"

const add = Option.lift2((a: number, b: number) => a + b)
console.log(add(Option.some(2), Option.some(3))) // => { _id: 'Option', _tag: 'Some', value: 5 }
console.log(add(Option.some(2), Option.none()))  // => { _id: 'Option', _tag: 'None' }
```

### Predicates & search

#### `contains`

Tests whether a `Some` holds a value equal to the given one, using default
structural equality.

```ts
import { Option } from "effect"

console.log(Option.contains(Option.some(2), 2)) // => true
console.log(Option.contains(Option.some(1), 2)) // => false
console.log(Option.contains(Option.none(), 2))  // => false
```

#### `containsWith`

Like `contains`, but using a custom `Equivalence`.

```ts
import { Equivalence, Option } from "effect"

const check = Option.containsWith(Equivalence.strictEqual<number>())
console.log(check(Option.some(2), 2)) // => true
console.log(check(Option.some(1), 2)) // => false
```

#### `exists`

Tests whether the value in a `Some` satisfies a predicate (or refinement);
`None` is always `false`.

```ts
import { Option } from "effect"

const isEven = (n: number) => n % 2 === 0
console.log(Option.exists(Option.some(2), isEven)) // => true
console.log(Option.exists(Option.some(1), isEven)) // => false
console.log(Option.exists(Option.none(), isEven))  // => false
```

### Equivalence & order

#### `makeEquivalence`

Builds an `Equivalence` for `Option<A>` from one for `A`. Two `None`s are equal;
`Some` and `None` differ.

```ts
import { Equivalence, Option } from "effect"

const eq = Option.makeEquivalence(Equivalence.strictEqual<number>())
console.log(eq(Option.some(1), Option.some(1))) // => true
console.log(eq(Option.some(1), Option.some(2))) // => false
console.log(eq(Option.none(), Option.none()))   // => true
```

#### `makeOrder`

Builds an `Order` for `Option<A>` from one for `A`. `None` sorts before any
`Some`.

```ts
import { Number as N, Option } from "effect"

const ord = Option.makeOrder(N.Order)
console.log(ord(Option.none(), Option.some(1))) // => -1
console.log(ord(Option.some(1), Option.none())) // => 1
console.log(ord(Option.some(1), Option.some(2))) // => -1
```

### Do-notation & generators

#### `Do`

The starting point for a do-notation chain: an `Option` of an empty record.

```ts
import { Option, pipe } from "effect"

console.log(
  pipe(
    Option.Do,
    Option.bind("x", () => Option.some(2)),
    Option.bind("y", () => Option.some(3))
  )
)
// => { _id: 'Option', _tag: 'Some', value: { x: 2, y: 3 } }
```

#### `bindTo`

Names the value of an existing `Option`, producing a single-key record — an
alternative entry point to `Do`.

```ts
import { Option, pipe } from "effect"

console.log(pipe(Option.some(2), Option.bindTo("x")))
// => { _id: 'Option', _tag: 'Some', value: { x: 2 } }
```

#### `bind`

Adds an `Option` value to the do-notation record; a `None` short-circuits the
whole chain.

```ts
import { Option, pipe } from "effect"

console.log(
  pipe(
    Option.Do,
    Option.bind("x", () => Option.some(2)),
    Option.bind("y", () => Option.none<number>())
  )
)
// => { _id: 'Option', _tag: 'None' }
```

#### `let`

Adds a computed plain (non-`Option`) value to the do-notation record.

```ts
import { Option, pipe } from "effect"

console.log(
  pipe(
    Option.Do,
    Option.bind("x", () => Option.some(2)),
    Option.let("double", ({ x }) => x * 2)
  )
)
// => { _id: 'Option', _tag: 'Some', value: { x: 2, double: 4 } }
```

#### `gen`

Generator-based syntax: each `yield*` unwraps a `Some` or short-circuits to
`None`; the return value is wrapped in `Some`.

```ts
import { Option } from "effect"

const person = Option.gen(function* () {
  const name = (yield* Option.some("John")).toUpperCase()
  const age = yield* Option.some(25)
  return { name, age }
})
console.log(person)
// => { _id: 'Option', _tag: 'Some', value: { name: 'JOHN', age: 25 } }
```

### Reducers & combiners

These advanced helpers build `Reducer`/`Combiner` instances for aggregating
collections of `Option`s.

#### `makeReducer`

Builds a `Reducer` that prioritizes the first non-`None` value and combines two
`Some`s with the given `Combiner` (initial value `None`).

```ts
import { Number, Option } from "effect"

const reducer = Option.makeReducer(Number.ReducerSum)
console.log(reducer.combineAll([Option.some(1), Option.none(), Option.some(2)]))
// => { _id: 'Option', _tag: 'Some', value: 3 }
```

#### `makeCombinerFailFast`

Builds a `Combiner` with fail-fast semantics: any `None` operand yields `None`.

```ts
import { Number, Option } from "effect"

const combiner = Option.makeCombinerFailFast(Number.ReducerSum)
console.log(combiner.combine(Option.some(1), Option.some(2))) // => { _id: 'Option', _tag: 'Some', value: 3 }
console.log(combiner.combine(Option.some(1), Option.none()))  // => { _id: 'Option', _tag: 'None' }
```

#### `makeReducerFailFast`

Lifts an existing `Reducer` into one over `Option` with fail-fast semantics
(initial value `Some(reducer.initialValue)`); any `None` aborts the result.

```ts
import { Number, Option } from "effect"

const reducer = Option.makeReducerFailFast(Number.ReducerSum)
console.log(reducer.combineAll([Option.some(1), Option.some(2)])) // => { _id: 'Option', _tag: 'Some', value: 3 }
console.log(reducer.combineAll([Option.some(1), Option.none()]))  // => { _id: 'Option', _tag: 'None' }
```