1/**
2 * Models a value that may be present or absent.
3 *
4 * An `Option<A>` is `Some<A>` when a value is available and `None` when it is
5 * not. This lets code handle missing values explicitly instead of relying on
6 * `null` or `undefined`. The module includes helpers for creating, checking,
7 * transforming, combining, and extracting optional values, plus conversions to
8 * and from common nullable or result-like shapes. It also includes `Option.gen`
9 * for writing small generator-based computations that stop at the first `None`.
10 *
11 * @since 2.0.0
12 */
13import * as Combiner from "./Combiner.ts"
14import * as Equal from "./Equal.ts"
15import * as Equivalence from "./Equivalence.ts"
16import type * as Filter from "./Filter.ts"
17import type { LazyArg } from "./Function.ts"
18import { constNull, constUndefined, dual, identity } from "./Function.ts"
19import type { TypeLambda } from "./HKT.ts"
20import type { Inspectable } from "./Inspectable.ts"
21import * as doNotation from "./internal/doNotation.ts"
22import * as option from "./internal/option.ts"
23import * as InternalRecord from "./internal/record.ts"
24import * as result from "./internal/result.ts"
25import type { Order } from "./Order.ts"
26import * as order from "./Order.ts"
27import type { Pipeable } from "./Pipeable.ts"
28import type { Predicate, Refinement } from "./Predicate.ts"
29import { isFunction } from "./Predicate.ts"
30import * as Reducer from "./Reducer.ts"
31import type { Result } from "./Result.ts"
32import type { Covariant, NoInfer, NotFunction } from "./Types.ts"
33import type * as Unify from "./Unify.ts"
34import type * as Gen from "./Utils.ts"
35
36const TypeId = "~effect/Option"
37
38/**
39 * The `Option` data type represents optional values. An `Option<A>` is either
40 * `Some<A>`, containing a value of type `A`, or `None`, representing absence.
41 *
42 * **When to use**
43 *
44 * Use to represent initial values that may not yet exist
45 * - Returning from partial functions (not defined for all inputs)
46 * - Managing optional fields in data structures
47 *
48 * @see {@link some} for creating a `Some`
49 * @see {@link none} for creating a `None`
50 * @see {@link match} for pattern matching
51 *
52 * @category models
53 * @since 2.0.0
54 */
55export type Option<A> = None<A> | Some<A>
56
57/**
58 * Represents the absence of a value within an {@link Option}.
59 *
60 * **When to use**
61 *
62 * Use as a type guard target when narrowing via {@link isNone}
63 *
64 * **Details**
65 *
66 * - `_tag` is always `"None"`
67 * - Implements `Pipeable`, `Inspectable`, and structural equality
68 *
69 * @see {@link isNone} to check if an `Option` is `None`
70 * @see {@link none} to construct a `None`
71 *
72 * @category models
73 * @since 2.0.0
74 */
75export interface None<out A> extends Pipeable, Inspectable {
76 readonly _tag: "None"
77 readonly _op: "None"
78 readonly valueOrUndefined: undefined
79 readonly [TypeId]: {
80 readonly _A: Covariant<A>
81 }
82 [Symbol.iterator](): OptionIterator<Option<A>>
83 [Unify.typeSymbol]?: unknown
84 [Unify.unifySymbol]?: OptionUnify<this>
85 [Unify.ignoreSymbol]?: OptionUnifyIgnore
86}
87
88/**
89 * Iterator protocol used to yield an `Option` inside {@link gen}, returning the
90 * contained value type back to the generator.
91 *
92 * **When to use**
93 *
94 * Use when defining or typing `[Symbol.iterator]()` for `Option` values so
95 * `yield*` can pass the contained value type back into `Option.gen`.
96 *
97 * @see {@link gen} for writing generator-based `Option` code that consumes this iterator protocol
98 *
99 * @category generators
100 * @since 4.0.0
101 */
102export interface OptionIterator<T extends Option<any>> {
103 next(
104 ...args: ReadonlyArray<any>
105 ): IteratorResult<T, Option.Value<T>>
106}
107
108/**
109 * Represents the presence of a value within an {@link Option}.
110 *
111 * **When to use**
112 *
113 * Use as a type guard target when narrowing via {@link isSome}
114 * - Access the inner value via `.value`
115 *
116 * **Details**
117 *
118 * - `_tag` is always `"Some"`
119 * - `.value` holds the contained value of type `A`
120 * - Implements `Pipeable`, `Inspectable`, and structural equality
121 *
122 * @see {@link isSome} to check if an `Option` is `Some`
123 * @see {@link some} to construct a `Some`
124 *
125 * @category models
126 * @since 2.0.0
127 */
128export interface Some<out A> extends Pipeable, Inspectable {
129 readonly _tag: "Some"
130 readonly _op: "Some"
131 readonly value: A
132 readonly valueOrUndefined: A
133 readonly [TypeId]: {
134 readonly _A: Covariant<A>
135 }
136 [Symbol.iterator](): OptionIterator<Option<A>>
137 [Unify.typeSymbol]?: unknown
138 [Unify.unifySymbol]?: OptionUnify<this>
139 [Unify.ignoreSymbol]?: OptionUnifyIgnore
140}
141
142/**
143 * Type-level unification support for `Option` values.
144 *
145 * **When to use**
146 *
147 * Use when extending Effect's type-level unification support for `Option`.
148 *
149 * **Details**
150 *
151 * This is used by Effect's `Unify` machinery to preserve the contained value
152 * type when generic code returns or combines `Option` values. Users normally
153 * do not need to reference this interface directly.
154 *
155 * @category models
156 * @since 2.0.0
157 */
158export interface OptionUnify<A extends { [Unify.typeSymbol]?: any }> {
159 Option?: () => A[Unify.typeSymbol] extends Option<infer A0> | infer _ ? Option<A0> : never
160}
161
162/**
163 * Namespace containing utility types for `Option`.
164 *
165 * **When to use**
166 *
167 * Use to access type-level helpers associated with `Option`.
168 *
169 * @since 2.0.0
170 */
171export declare namespace Option {
172 /**
173 * Extracts the type of the value contained in an `Option`.
174 *
175 * **When to use**
176 *
177 * Use to infer the inner value type from an existing `Option` type.
178 *
179 * **Example** (Extracting the value type)
180 *
181 * ```ts import.meta.vitest
182 * import { Option } from "effect"
183 *
184 * const myOption: Option.Option<string> = Option.some("value")
185 * type MyType = Option.Option.Value<typeof myOption>
186 *
187 * const witness: MyType = "value"
188 * ```
189 *
190 * @category utility types
191 * @since 2.0.0
192 */
193 export type Value<T extends Option<any>> = [T] extends [Option<infer _A>] ? _A : never
194}
195
196/**
197 * Marker interface used by Effect's `Unify` machinery for `Option` values.
198 *
199 * **When to use**
200 *
201 * Use when marking generic code so `Option` unification should be ignored.
202 *
203 * **Details**
204 *
205 * This supports type-level unification behavior for `Option`. Users normally
206 * do not need to reference this interface directly.
207 *
208 * @category models
209 * @since 2.0.0
210 */
211export interface OptionUnifyIgnore {}
212
213/**
214 * Type lambda interface for higher-kinded type encodings with `Option`.
215 *
216 * **When to use**
217 *
218 * Use when defining higher-kinded abstractions that must accept optional-value
219 * types as one of their type-lambda inputs.
220 *
221 * @category utility types
222 * @since 2.0.0
223 */
224export interface OptionTypeLambda extends TypeLambda {
225 readonly type: Option<this["Target"]>
226}
227
228/**
229 * Creates an `Option` representing the absence of a value.
230 *
231 * **When to use**
232 *
233 * Use to represent a missing or uninitialized value, such as returning "no
234 * result" from a function.
235 *
236 * **Details**
237 *
238 * - Returns `Option<never>`, which is a subtype of `Option<A>` for any `A`
239 * - Always returns the same singleton instance
240 *
241 * **Example** (Creating an empty Option)
242 *
243 * ```ts import.meta.vitest
244 * import { Option } from "effect"
245 *
246 * // ┌─── Option<never>
247 * // ▼
248 * const noValue = Option.none() // => Option.none()
249 * ```
250 *
251 * @see {@link some} for the opposite operation.
252 *
253 * @category constructors
254 * @since 2.0.0
255 */
256export const none = <A = never>(): Option<A> => option.none
257
258/**
259 * Wraps the given value into an `Option` to represent its presence.
260 *
261 * **When to use**
262 *
263 * Use to wrap a known present value as `Option`
264 * - Returning a successful result from a partial function
265 *
266 * **Details**
267 *
268 * - Always returns `Some<A>`
269 * - Does not filter `null` or `undefined`; use {@link fromNullishOr} for that
270 *
271 * **Example** (Wrapping a value)
272 *
273 * ```ts import.meta.vitest
274 * import { Option } from "effect"
275 *
276 * // ┌─── Option<number>
277 * // ▼
278 * const value = Option.some(1) // => Option.some(1)
279 * ```
280 *
281 * @see {@link none} for the opposite operation.
282 *
283 * @category constructors
284 * @since 2.0.0
285 */
286export const some: <A>(value: A) => Option<A> = option.some
287
288/**
289 * Determines whether the given value is an `Option`.
290 *
291 * **When to use**
292 *
293 * Use to validate unknown values at runtime boundaries, such as type-narrowing
294 * in union types.
295 *
296 * **Details**
297 *
298 * - Returns `true` for both `Some` and `None` instances
299 * - Acts as a type guard, narrowing the input to `Option<unknown>`
300 *
301 * **Example** (Checking if a value is an Option)
302 *
303 * ```ts import.meta.vitest
304 * import { Option } from "effect"
305 *
306 * Option.isOption(Option.some(1)) // => true
307 * Option.isOption(Option.none()) // => true
308 * Option.isOption({}) // => false
309 * ```
310 *
311 * @see {@link isNone} to check for `None` specifically
312 * @see {@link isSome} to check for `Some` specifically
313 *
314 * @category guards
315 * @since 2.0.0
316 */
317export const isOption: (input: unknown) => input is Option<unknown> = option.isOption
318
319/**
320 * Checks whether an `Option` is `None` (absent).
321 *
322 * **When to use**
323 *
324 * Use when you need to branch on an absent `Option` before accessing `.value`.
325 *
326 * **Details**
327 *
328 * - Acts as a type guard, narrowing to `None<A>`
329 *
330 * **Example** (Checking for None)
331 *
332 * ```ts import.meta.vitest
333 * import { Option } from "effect"
334 *
335 * Option.isNone(Option.some(1)) // => false
336 * Option.isNone(Option.none()) // => true
337 * ```
338 *
339 * @see {@link isSome} for the opposite check.
340 *
341 * @category guards
342 * @since 2.0.0
343 */
344export const isNone: <A>(self: Option<A>) => self is None<A> = option.isNone
345
346/**
347 * Checks whether an `Option` contains a value (`Some`).
348 *
349 * **When to use**
350 *
351 * Use when you need to branch on a present `Option` before accessing `.value`.
352 *
353 * **Details**
354 *
355 * - Acts as a type guard, narrowing to `Some<A>`
356 *
357 * **Example** (Checking for Some)
358 *
359 * ```ts import.meta.vitest
360 * import { Option } from "effect"
361 *
362 * Option.isSome(Option.some(1)) // => true
363 * Option.isSome(Option.none()) // => false
364 * ```
365 *
366 * @see {@link isNone} for the opposite check.
367 *
368 * @category guards
369 * @since 2.0.0
370 */
371export const isSome: <A>(self: Option<A>) => self is Some<A> = option.isSome
372
373/**
374 * Pattern-matches on an `Option`, handling both `None` and `Some` cases.
375 *
376 * **When to use**
377 *
378 * Use when you need to handle both `Some` and `None` in one expression and
379 * transform an `Option` into a plain value.
380 *
381 * **Details**
382 *
383 * - If `None`, calls `onNone` and returns its result
384 * - If `Some`, calls `onSome` with the value and returns its result
385 * - Supports the `dual` API (data-last and data-first)
386 *
387 * **Example** (Matching on an Option)
388 *
389 * ```ts import.meta.vitest
390 * import { Option } from "effect"
391 *
392 * Option.match(Option.some(1), {
393 * onNone: () => "Option is empty",
394 * onSome: (value) => `Option has a value: ${value}`
395 * }) // => "Option has a value: 1"
396 * ```
397 *
398 * @see {@link getOrElse} for unwrapping with a default
399 *
400 * @category pattern matching
401 * @since 2.0.0
402 */
403export const match: {
404 <B, A, C = B>(options: {
405 readonly onNone: LazyArg<B>
406 readonly onSome: (a: A) => C
407 }): (self: Option<A>) => B | C
408 <A, B, C = B>(self: Option<A>, options: {
409 readonly onNone: LazyArg<B>
410 readonly onSome: (a: A) => C
411 }): B | C
412} = dual(
413 2,
414 <A, B, C = B>(self: Option<A>, { onNone, onSome }: {
415 readonly onNone: LazyArg<B>
416 readonly onSome: (a: A) => C
417 }): B | C => isNone(self) ? onNone() : onSome(self.value)
418)
419
420/**
421 * Converts an `Option`-returning function into a type guard (refinement).
422 *
423 * **When to use**
424 *
425 * Use when you need to turn an `Option`-returning parser into a type-narrowing
426 * predicate, such as for `Array.prototype.filter`.
427 *
428 * **Details**
429 *
430 * - Returns `true` when the original function returns `Some`
431 * - Returns `false` when the original function returns `None`
432 * - Narrows the input type to `B` on success
433 *
434 * **Example** (Converting a parser to a type guard)
435 *
436 * ```ts import.meta.vitest
437 * import { Option } from "effect"
438 *
439 * type MyData = string | number
440 *
441 * const parseString = (data: MyData): Option.Option<string> =>
442 * typeof data === "string" ? Option.some(data) : Option.none()
443 *
444 * // ┌─── (a: MyData) => a is string
445 * // ▼
446 * const isString = Option.toRefinement(parseString)
447 *
448 * isString("a") // => true
449 * isString(1) // => false
450 * ```
451 *
452 * @see {@link liftPredicate} for the reverse direction
453 *
454 * @category converting
455 * @since 2.0.0
456 */
457export const toRefinement = <A, B extends A>(f: (a: A) => Option<B>): (a: A) => a is B => (a: A): a is B => isSome(f(a))
458
459/**
460 * Wraps the first element of an `Iterable` in a `Some`, or returns `None` if
461 * the iterable is empty.
462 *
463 * **When to use**
464 *
465 * Use when you need to safely extract the head of a collection, including
466 * generators or lazy iterables.
467 *
468 * **Details**
469 *
470 * - Only consumes the first element; does not iterate the rest
471 * - Returns `None` for empty iterables
472 *
473 * **Example** (Getting the first element)
474 *
475 * ```ts import.meta.vitest
476 * import { Option } from "effect"
477 *
478 * Option.fromIterable([1, 2, 3]) // => Option.some(1)
479 * Option.fromIterable([]) // => Option.none()
480 * ```
481 *
482 * @see {@link toArray} for the inverse direction
483 *
484 * @category constructors
485 * @since 2.0.0
486 */
487export const fromIterable = <A>(collection: Iterable<A>): Option<A> => {
488 for (const a of collection) {
489 return some(a)
490 }
491 return none()
492}
493
494/**
495 * Converts a `Result` into an `Option`, keeping only the success value.
496 *
497 * **When to use**
498 *
499 * Use when you need to discard a `Result` failure and keep only the success
500 * value as an `Option`.
501 *
502 * **Details**
503 *
504 * - `Success` becomes `Some` with the success value
505 * - `Failure` becomes `None` and the failure value is discarded
506 *
507 * **Example** (Extracting the success side)
508 *
509 * ```ts import.meta.vitest
510 * import { Option, Result } from "effect"
511 *
512 * Option.getSuccess(Result.succeed("ok")) // => Option.some("ok")
513 * Option.getSuccess(Result.fail("err")) // => Option.none()
514 * ```
515 *
516 * @see {@link getFailure} for the opposite operation.
517 *
518 * @category converting
519 * @since 4.0.0
520 */
521export const getSuccess: <A, E>(self: Result<A, E>) => Option<A> = result.getSuccess
522
523/**
524 * Converts a `Result` into an `Option`, keeping only the failure value.
525 *
526 * **When to use**
527 *
528 * Use when you need to discard a `Result` success and keep only the failure
529 * value as an `Option`.
530 *
531 * **Details**
532 *
533 * - `Failure` becomes `Some` with the failure value
534 * - `Success` becomes `None` and the success value is discarded
535 *
536 * **Example** (Extracting the failure side)
537 *
538 * ```ts import.meta.vitest
539 * import { Option, Result } from "effect"
540 *
541 * Option.getFailure(Result.succeed("ok")) // => Option.none()
542 * Option.getFailure(Result.fail("err")) // => Option.some("err")
543 * ```
544 *
545 * @see {@link getSuccess} for the opposite operation.
546 *
547 * @category converting
548 * @since 4.0.0
549 */
550export const getFailure: <A, E>(self: Result<A, E>) => Option<E> = result.getFailure
551
552/**
553 * Extracts the value from a `Some`, or evaluates a fallback thunk on `None`.
554 *
555 * **When to use**
556 *
557 * Use when providing a default value for an absent `Option`
558 * - Unwrapping with lazy evaluation of the fallback
559 *
560 * **Details**
561 *
562 * - `Some` → returns the inner value
563 * - `None` → calls `onNone()` and returns its result
564 * - `onNone` is only called when needed (lazy)
565 *
566 * **Example** (Unwrapping with a fallback)
567 *
568 * ```ts import.meta.vitest
569 * import { Option } from "effect"
570 *
571 * Option.some(1).pipe(Option.getOrElse(() => 0)) // => 1
572 * Option.none().pipe(Option.getOrElse(() => 0)) // => 0
573 * ```
574 *
575 * @see {@link getOrNull} to fall back to `null`
576 * @see {@link getOrUndefined} to fall back to `undefined`
577 * @see {@link getOrThrow} to throw on `None`
578 *
579 * @category getters
580 * @since 2.0.0
581 */
582export const getOrElse: {
583 <B>(onNone: LazyArg<B>): <A>(self: Option<A>) => B | A
584 <A, B>(self: Option<A>, onNone: LazyArg<B>): A | B
585} = dual(
586 2,
587 <A, B>(self: Option<A>, onNone: LazyArg<B>): A | B => isNone(self) ? onNone() : self.value
588)
589
590/**
591 * Returns the fallback `Option` if `self` is `None`; otherwise returns `self`.
592 *
593 * **When to use**
594 *
595 * Use when you need a lazy fallback `Option`, such as when building priority
596 * chains of optional values.
597 *
598 * **Details**
599 *
600 * - `Some` → returns `self` unchanged
601 * - `None` → evaluates and returns `that()`
602 * - `that` is lazily evaluated
603 *
604 * **Example** (Providing a fallback Option)
605 *
606 * ```ts import.meta.vitest
607 * import { Option } from "effect"
608 *
609 * Option.none().pipe(Option.orElse(() => Option.some("b"))) // => Option.some("b")
610 * Option.some("a").pipe(Option.orElse(() => Option.some("b"))) // => Option.some("a")
611 * ```
612 *
613 * @see {@link orElseSome} to wrap the fallback value in `Some` automatically
614 * @see {@link firstSomeOf} to pick the first `Some` from a collection
615 *
616 * @category error handling
617 * @since 2.0.0
618 */
619export const orElse: {
620 <B>(that: LazyArg<Option<B>>): <A>(self: Option<A>) => Option<B | A>
621 <A, B>(self: Option<A>, that: LazyArg<Option<B>>): Option<A | B>
622} = dual(
623 2,
624 <A, B>(self: Option<A>, that: LazyArg<Option<B>>): Option<A | B> => isNone(self) ? that() : self
625)
626
627/**
628 * Returns `Some` of the fallback value if `self` is `None`; otherwise returns
629 * `self`.
630 *
631 * **When to use**
632 *
633 * Use when providing a default plain value (not an `Option`) as fallback
634 *
635 * **Details**
636 *
637 * - `Some` → returns `self` unchanged
638 * - `None` → calls `onNone()`, wraps result in `Some`, and returns it
639 *
640 * **Example** (Providing a fallback value)
641 *
642 * ```ts import.meta.vitest
643 * import { Option } from "effect"
644 *
645 * Option.none().pipe(Option.orElseSome(() => "b")) // => Option.some("b")
646 * Option.some("a").pipe(Option.orElseSome(() => "b")) // => Option.some("a")
647 * ```
648 *
649 * @see {@link orElse} when the fallback is itself an `Option`
650 *
651 * @category error handling
652 * @since 2.0.0
653 */
654export const orElseSome: {
655 <B>(onNone: LazyArg<B>): <A>(self: Option<A>) => Option<B | A>
656 <A, B>(self: Option<A>, onNone: LazyArg<B>): Option<A | B>
657} = dual(
658 2,
659 <A, B>(self: Option<A>, onNone: LazyArg<B>): Option<A | B> => isNone(self) ? some(onNone()) : self
660)
661
662/**
663 * Returns the first available value and marks whether it came from the fallback.
664 *
665 * **When to use**
666 *
667 * Use when you need to know whether a present value came from the primary or
668 * fallback `Option`.
669 *
670 * **Details**
671 *
672 * - `self` is `Some` → `Some(Result.fail(value))` (value from primary)
673 * - `self` is `None`, `that()` is `Some` → `Some(Result.succeed(value))` (value from fallback)
674 * - Both `None` → `None`
675 *
676 * **Example** (Tracking value source)
677 *
678 * ```ts import.meta.vitest
679 * import { Option, Result } from "effect"
680 *
681 * const fallback = () => Option.some("fallback")
682 *
683 * Option.orElseResult(Option.some("primary"), fallback) // => Option.some(Result.fail("primary"))
684 * Option.orElseResult(Option.none(), fallback) // => Option.some(Result.succeed("fallback"))
685 * ```
686 *
687 * @see {@link orElse} for the simpler variant without source tracking
688 *
689 * @category error handling
690 * @since 4.0.0
691 */
692export const orElseResult: {
693 <B>(that: LazyArg<Option<B>>): <A>(self: Option<A>) => Option<Result<B, A>>
694 <A, B>(self: Option<A>, that: LazyArg<Option<B>>): Option<Result<B, A>>
695} = dual(
696 2,
697 <A, B>(self: Option<A>, that: LazyArg<Option<B>>): Option<Result<B, A>> =>
698 isNone(self) ? map(that(), result.succeed) : map(self, result.fail)
699)
700
701/**
702 * Returns the first `Some` found in an iterable of `Option`s, or `None` if
703 * all are `None`.
704 *
705 * **When to use**
706 *
707 * Use when you need the first available `Some` value from a priority list.
708 *
709 * **Details**
710 *
711 * - Short-circuits on the first `Some`
712 * - Returns `None` only when every element is `None`
713 *
714 * **Example** (Finding the first Some)
715 *
716 * ```ts import.meta.vitest
717 * import { Option } from "effect"
718 *
719 * Option.firstSomeOf([
720 * Option.none(),
721 * Option.some(1),
722 * Option.some(2)
723 * ]) // => Option.some(1)
724 * ```
725 *
726 * @see {@link orElse} for a two-option fallback
727 *
728 * @category error handling
729 * @since 2.0.0
730 */
731export const firstSomeOf = <T, C extends Iterable<Option<T>> = Iterable<Option<T>>>(
732 collection: C
733): [C] extends [Iterable<Option<infer A>>] ? Option<A> : never => {
734 let out: Option<unknown> = none()
735 for (out of collection) {
736 if (isSome(out)) {
737 return out as any
738 }
739 }
740 return out as any
741}
742
743/**
744 * Converts a nullable value (`null` or `undefined`) into an `Option`.
745 *
746 * **When to use**
747 *
748 * Use when you need JavaScript nullish values to become absence at an API
749 * boundary while all other values, including falsy ones, remain present.
750 *
751 * **Details**
752 *
753 * - `null` or `undefined` → `None`
754 * - Any other value → `Some` (typed as `NonNullable<A>`)
755 *
756 * **Example** (Converting nullable values to an Option)
757 *
758 * ```ts import.meta.vitest
759 * import { Option } from "effect"
760 *
761 * Option.fromNullishOr(undefined) // => Option.none()
762 * Option.fromNullishOr(null) // => Option.none()
763 * Option.fromNullishOr(1) // => Option.some(1)
764 * ```
765 *
766 * @see {@link fromNullOr} to only treat `null` as absent
767 * @see {@link fromUndefinedOr} to only treat `undefined` as absent
768 * @see {@link liftNullishOr} to lift a nullable-returning function
769 *
770 * @category converting
771 * @since 4.0.0
772 */
773export const fromNullishOr = <A>(
774 a: A
775): Option<NonNullable<A>> => (a == null ? none() : some(a as NonNullable<A>))
776
777/**
778 * Converts a possibly `undefined` value into an `Option`, leaving `null`
779 * as a valid `Some`.
780 *
781 * **When to use**
782 *
783 * Use when you want to treat only `undefined` as absent while preserving `null`
784 * as a meaningful value.
785 *
786 * **Details**
787 *
788 * - `undefined` → `None`
789 * - Any other value (including `null`) → `Some`
790 *
791 * **Example** (Converting possibly undefined values to an Option)
792 *
793 * ```ts import.meta.vitest
794 * import { Option } from "effect"
795 *
796 * Option.fromUndefinedOr(undefined) // => Option.none()
797 * Option.fromUndefinedOr(null) // => Option.some(null)
798 * Option.fromUndefinedOr(42) // => Option.some(42)
799 * ```
800 *
801 * @see {@link fromNullishOr} to treat both `null` and `undefined` as absent
802 * @see {@link fromNullOr} to only treat `null` as absent
803 *
804 * @category converting
805 * @since 4.0.0
806 */
807export const fromUndefinedOr = <A>(
808 a: A
809): Option<Exclude<A, undefined>> => (a === undefined ? none() : some(a as Exclude<A, undefined>))
810
811/**
812 * Converts a possibly `null` value into an `Option`, leaving `undefined`
813 * as a valid `Some`.
814 *
815 * **When to use**
816 *
817 * Use when you want to treat only `null` as absent while preserving
818 * `undefined` as a meaningful value.
819 *
820 * **Details**
821 *
822 * - `null` → `None`
823 * - Any other value (including `undefined`) → `Some`
824 *
825 * **Example** (Converting possibly null values to an Option)
826 *
827 * ```ts import.meta.vitest
828 * import { Option } from "effect"
829 *
830 * Option.fromNullOr(null) // => Option.none()
831 * Option.fromNullOr(undefined) // => Option.some(undefined)
832 * Option.fromNullOr(42) // => Option.some(42)
833 * ```
834 *
835 * @see {@link fromNullishOr} to treat both `null` and `undefined` as absent
836 * @see {@link fromUndefinedOr} to only treat `undefined` as absent
837 *
838 * @category converting
839 * @since 4.0.0
840 */
841export const fromNullOr = <A>(
842 a: A
843): Option<Exclude<A, null>> => (a === null ? none() : some(a as Exclude<A, null>))
844
845/**
846 * Lifts a function that may return `null` or `undefined` into one that returns
847 * an `Option`.
848 *
849 * **When to use**
850 *
851 * Use to wrap existing nullable-returning functions for use in `Option` pipelines
852 *
853 * **Details**
854 *
855 * - Calls the original function with the given arguments
856 * - Wraps the result via {@link fromNullishOr}
857 *
858 * **Example** (Lifting a parser)
859 *
860 * ```ts import.meta.vitest
861 * import { Option } from "effect"
862 *
863 * const parse = (s: string): number | undefined => {
864 * const n = parseFloat(s)
865 * return isNaN(n) ? undefined : n
866 * }
867 *
868 * const parseOption = Option.liftNullishOr(parse)
869 *
870 * parseOption("1") // => Option.some(1)
871 * parseOption("not a number") // => Option.none()
872 * ```
873 *
874 * @see {@link fromNullishOr} for converting a single value
875 * @see {@link liftThrowable} for functions that throw instead
876 *
877 * @category converting
878 * @since 4.0.0
879 */
880export const liftNullishOr = <A extends ReadonlyArray<unknown>, B>(
881 f: (...a: A) => B
882): (...a: A) => Option<NonNullable<B>> =>
883(...a) => fromNullishOr(f(...a))
884
885/**
886 * Extracts the value from a `Some`, or returns `null` for `None`.
887 *
888 * **When to use**
889 *
890 * Use when you need to pass absent `Option` values to APIs that expect `null`.
891 *
892 * **Details**
893 *
894 * - `Some` → the inner value
895 * - `None` → `null`
896 *
897 * **Example** (Unwrapping to null)
898 *
899 * ```ts import.meta.vitest
900 * import { Option } from "effect"
901 *
902 * Option.getOrNull(Option.some(1)) // => 1
903 * Option.getOrNull(Option.none()) // => null
904 * ```
905 *
906 * @see {@link getOrUndefined} to return `undefined` instead
907 * @see {@link getOrElse} for a custom fallback
908 *
909 * @category getters
910 * @since 2.0.0
911 */
912export const getOrNull: <A>(self: Option<A>) => A | null = getOrElse(constNull)
913
914/**
915 * Extracts the value from a `Some`, or returns `undefined` for `None`.
916 *
917 * **When to use**
918 *
919 * Use when you need to pass absent `Option` values to APIs that expect
920 * `undefined`.
921 *
922 * **Details**
923 *
924 * - `Some` → the inner value
925 * - `None` → `undefined`
926 *
927 * **Example** (Unwrapping to undefined)
928 *
929 * ```ts import.meta.vitest
930 * import { Option } from "effect"
931 *
932 * Option.getOrUndefined(Option.some(1)) // => 1
933 * Option.getOrUndefined(Option.none()) // => undefined
934 * ```
935 *
936 * @see {@link getOrNull} to return `null` instead
937 * @see {@link getOrElse} for a custom fallback
938 *
939 * @category getters
940 * @since 2.0.0
941 */
942export const getOrUndefined: <A>(self: Option<A>) => A | undefined = getOrElse(constUndefined)
943
944/**
945 * Lifts a function that may throw into one that returns an `Option`.
946 *
947 * **When to use**
948 *
949 * Use to wrap exception-throwing APIs (e.g. `JSON.parse`) for safe usage
950 *
951 * **Details**
952 *
953 * - If the function returns normally → `Some` with the result
954 * - If the function throws → `None` (exception is swallowed)
955 *
956 * **Example** (Lifting JSON.parse)
957 *
958 * ```ts import.meta.vitest
959 * import { Option } from "effect"
960 *
961 * const parse = Option.liftThrowable(JSON.parse)
962 *
963 * parse("1") // => Option.some(1)
964 * parse("") // => Option.none()
965 * ```
966 *
967 * @see {@link liftNullishOr} for nullable-returning functions
968 *
969 * @category converting
970 * @since 2.0.0
971 */
972export const liftThrowable = <A extends ReadonlyArray<unknown>, B>(
973 f: (...a: A) => B
974): (...a: A) => Option<B> =>
975(...a) => {
976 try {
977 return some(f(...a))
978 } catch {
979 return none()
980 }
981}
982
983/**
984 * Extracts the value from a `Some`, or throws a custom error for `None`.
985 *
986 * **When to use**
987 *
988 * Use when you need fail-fast unwrapping of an `Option` for unexpected absence
989 * and want to provide a descriptive debugging error.
990 *
991 * **Details**
992 *
993 * - `Some` → returns the inner value
994 * - `None` → throws the value returned by `onNone()`
995 *
996 * **Example** (Throwing a custom error)
997 *
998 * ```ts import.meta.vitest
999 * import { Option, Result } from "effect"
1000 *
1001 * Option.getOrThrowWith(Option.some(1), () => new Error("missing")) // => 1
1002 *
1003 * const failure = Result.try({
1004 * try: () => Option.getOrThrowWith(Option.none(), () => new Error("missing")),
1005 * catch: (error) => (error as Error).message
1006 * })
1007 * Result.getFailure(failure).pipe(Option.getOrElse(() => "no error")) // => "missing"
1008 * ```
1009 *
1010 * @see {@link getOrThrow} for a version with a default error
1011 * @see {@link getOrElse} for a non-throwing alternative
1012 *
1013 * @category converting
1014 * @since 2.0.0
1015 */
1016export const getOrThrowWith: {
1017 (onNone: () => unknown): <A>(self: Option<A>) => A
1018 <A>(self: Option<A>, onNone: () => unknown): A
1019} = dual(2, <A>(self: Option<A>, onNone: () => unknown): A => {
1020 if (isSome(self)) {
1021 return self.value
1022 }
1023 throw onNone()
1024})
1025
1026/**
1027 * Extracts the value from a `Some`, or throws a default `Error` for `None`.
1028 *
1029 * **When to use**
1030 *
1031 * Use when you need quick fail-fast unwrapping of an `Option` and a generic
1032 * error is acceptable.
1033 *
1034 * **Details**
1035 *
1036 * - `Some` → returns the inner value
1037 * - `None` → throws `new Error("getOrThrow called on a None")`
1038 *
1039 * **Example** (Throwing a default error)
1040 *
1041 * ```ts import.meta.vitest
1042 * import { Option, Result } from "effect"
1043 *
1044 * Option.getOrThrow(Option.some(1)) // => 1
1045 *
1046 * const failure = Result.try({
1047 * try: () => Option.getOrThrow(Option.none()),
1048 * catch: (error) => (error as Error).message
1049 * })
1050 * Result.getFailure(failure).pipe(Option.getOrElse(() => "no error")) // => "getOrThrow called on a None"
1051 * ```
1052 *
1053 * @see {@link getOrThrowWith} for a custom error
1054 * @see {@link getOrElse} for a non-throwing alternative
1055 *
1056 * @category converting
1057 * @since 2.0.0
1058 */
1059export const getOrThrow: <A>(self: Option<A>) => A = getOrThrowWith(() => new Error("getOrThrow called on a None"))
1060
1061/**
1062 * Transforms the value inside a `Some` using the provided function, leaving
1063 * `None` unchanged.
1064 *
1065 * **When to use**
1066 *
1067 * Use to apply a pure transformation to an `Option`'s present value, especially
1068 * when chaining transformations in a pipeline.
1069 *
1070 * **Details**
1071 *
1072 * - `Some` → applies `f` and wraps the result in a new `Some`
1073 * - `None` → returns `None` unchanged
1074 *
1075 * **Example** (Mapping over an Option)
1076 *
1077 * ```ts import.meta.vitest
1078 * import { Option } from "effect"
1079 *
1080 * Option.map(Option.some(2), (n) => n * 2) // => Option.some(4)
1081 * Option.map(Option.none(), (n: number) => n * 2) // => Option.none()
1082 * ```
1083 *
1084 * @see {@link flatMap} when `f` returns an `Option`
1085 * @see {@link as} to replace the value with a constant
1086 *
1087 * @category mapping
1088 * @since 2.0.0
1089 */
1090export const map: {
1091 <A, B>(f: (a: A) => B): (self: Option<A>) => Option<B>
1092 <A, B>(self: Option<A>, f: (a: A) => B): Option<B>
1093} = dual(
1094 2,
1095 <A, B>(self: Option<A>, f: (a: A) => B): Option<B> => isNone(self) ? none() : some(f(self.value))
1096)
1097
1098/**
1099 * Replaces the value inside a `Some` with a constant, leaving `None` unchanged.
1100 *
1101 * **When to use**
1102 *
1103 * Use when you need to replace a present `Option` value while preserving
1104 * whether it was `Some` or `None`.
1105 *
1106 * **Example** (Replacing a value)
1107 *
1108 * ```ts import.meta.vitest
1109 * import { Option } from "effect"
1110 *
1111 * Option.as(Option.some(42), "new value") // => Option.some("new value")
1112 * Option.as(Option.none(), "new value") // => Option.none()
1113 * ```
1114 *
1115 * @see {@link asVoid} to replace with `undefined`
1116 * @see {@link map} for a general transformation
1117 *
1118 * @category mapping
1119 * @since 2.0.0
1120 */
1121export const as: {
1122 <B>(b: B): <X>(self: Option<X>) => Option<B>
1123 <X, B>(self: Option<X>, b: B): Option<B>
1124} = dual(2, <X, B>(self: Option<X>, b: B): Option<B> => map(self, () => b))
1125
1126/**
1127 * Replaces the value inside a `Some` with `void` (`undefined`), leaving `None`
1128 * unchanged.
1129 *
1130 * **When to use**
1131 *
1132 * Use when you need to discard a present `Option` value while preserving
1133 * whether it was `Some` or `None`.
1134 *
1135 * **Example** (Voiding the value)
1136 *
1137 * ```ts import.meta.vitest
1138 * import { Option } from "effect"
1139 *
1140 * Option.asVoid(Option.some(42)) // => Option.some(undefined)
1141 * Option.asVoid(Option.none()) // => Option.none()
1142 * ```
1143 *
1144 * @see {@link as} to replace with a specific constant
1145 *
1146 * @category mapping
1147 * @since 2.0.0
1148 */
1149export const asVoid: <_>(self: Option<_>) => Option<void> = as(undefined)
1150
1151const void_: Option<void> = some(undefined)
1152export {
1153 /**
1154 * Provides a pre-built `Some(undefined)` constant.
1155 *
1156 * **When to use**
1157 *
1158 * Use to return a "success with no meaningful value" from an `Option`-returning function
1159 *
1160 * **Example** (Referencing Option.void)
1161 *
1162 * ```ts import.meta.vitest
1163 * import { Option } from "effect"
1164 *
1165 * Option.void // => Option.some(undefined)
1166 * ```
1167 *
1168 * @see {@link asVoid} to convert an existing `Option` to `Option<void>`
1169 *
1170 * @category constructors
1171 * @since 2.0.0
1172 */
1173 void_ as void
1174}
1175
1176/**
1177 * Applies a function that returns an `Option` to the value of a `Some`,
1178 * flattening the result. Returns `None` if the input is `None`.
1179 *
1180 * **When to use**
1181 *
1182 * Use when you need to chain dependent `Option` computations where each step
1183 * may return `None`.
1184 *
1185 * **Details**
1186 *
1187 * - `Some` → applies `f` to the value and returns its `Option` result
1188 * - `None` → returns `None` without calling `f`
1189 * - Equivalent to `map` followed by {@link flatten}
1190 *
1191 * **Example** (Chaining optional lookups)
1192 *
1193 * ```ts import.meta.vitest
1194 * import { Option } from "effect"
1195 *
1196 * interface User {
1197 * readonly name: string
1198 * readonly address: Option.Option<{ readonly street: Option.Option<string> }>
1199 * }
1200 *
1201 * const user: User = {
1202 * name: "John",
1203 * address: Option.some({ street: Option.some("123 Main St") })
1204 * }
1205 *
1206 * user.address.pipe(
1207 * Option.flatMap((addr) => addr.street)
1208 * ) // => Option.some("123 Main St")
1209 * ```
1210 *
1211 * @see {@link map} when `f` returns a plain value
1212 * @see {@link andThen} for a more flexible variant
1213 * @see {@link flatten} to unwrap a nested `Option<Option<A>>`
1214 *
1215 * @category sequencing
1216 * @since 2.0.0
1217 */
1218export const flatMap: {
1219 <A, B>(f: (a: A) => Option<B>): (self: Option<A>) => Option<B>
1220 <A, B>(self: Option<A>, f: (a: A) => Option<B>): Option<B>
1221} = dual(
1222 2,
1223 <A, B>(self: Option<A>, f: (a: A) => Option<B>): Option<B> => isNone(self) ? none() : f(self.value)
1224)
1225
1226/**
1227 * Chains a second computation onto an `Option`. The second value can be a
1228 * plain value, an `Option`, or a function returning either.
1229 *
1230 * **When to use**
1231 *
1232 * Use when you need to chain an `Option` with a next step that may be another
1233 * `Option`, a plain value, or a function.
1234 *
1235 * **Details**
1236 *
1237 * - If `self` is `None`, returns `None` immediately
1238 * - If `f` is a function, calls it with the `Some` value
1239 * - If `f` returns an `Option`, returns it as-is; if a plain value, wraps in `Some`
1240 * - If `f` is not a function, uses it directly (same wrapping rules)
1241 *
1242 * **Example** (Chaining with andThen)
1243 *
1244 * ```ts import.meta.vitest
1245 * import { Option } from "effect"
1246 *
1247 * // Chain with a function returning Option
1248 * Option.andThen(Option.some(5), (x) => Option.some(x * 2)) // => Option.some(10)
1249 *
1250 * // Chain with a static value
1251 * Option.andThen(Option.some(5), "hello") // => Option.some("hello")
1252 *
1253 * // Chain with None - skips
1254 * Option.andThen(Option.none(), (x) => Option.some(x * 2)) // => Option.none()
1255 * ```
1256 *
1257 * @see {@link flatMap} for the standard monadic bind
1258 * @see {@link map} when you always return a plain value
1259 *
1260 * @category sequencing
1261 * @since 2.0.0
1262 */
1263export const andThen: {
1264 <A, B>(f: (a: A) => Option<B>): (self: Option<A>) => Option<B>
1265 <B>(f: Option<B>): <A>(self: Option<A>) => Option<B>
1266 <A, B>(f: (a: A) => B): (self: Option<A>) => Option<B>
1267 <B>(f: NotFunction<B>): <A>(self: Option<A>) => Option<B>
1268 <A, B>(self: Option<A>, f: (a: A) => Option<B>): Option<B>
1269 <A, B>(self: Option<A>, f: Option<B>): Option<B>
1270 <A, B>(self: Option<A>, f: (a: A) => B): Option<B>
1271 <A, B>(self: Option<A>, f: NotFunction<B>): Option<B>
1272} = dual(
1273 2,
1274 <A, B>(self: Option<A>, f: (a: A) => Option<B> | Option<B>): Option<B> =>
1275 flatMap(self, (a) => {
1276 const b = isFunction(f) ? f(a) : f
1277 return isOption(b) ? b : some(b)
1278 })
1279)
1280
1281/**
1282 * Combines {@link flatMap} with {@link fromNullishOr}: applies a function that
1283 * may return `null`/`undefined` to the value of a `Some`.
1284 *
1285 * **When to use**
1286 *
1287 * Use when you need to chain optional computations that use `null` or
1288 * `undefined` instead of `Option`, such as nested property access.
1289 *
1290 * **Details**
1291 *
1292 * - `None` → `None`
1293 * - `Some` → applies `f`, then wraps via {@link fromNullishOr}
1294 *
1295 * **Example** (Navigating optional properties)
1296 *
1297 * ```ts import.meta.vitest
1298 * import { Option } from "effect"
1299 *
1300 * interface Employee {
1301 * company?: { address?: { street?: { name?: string } } }
1302 * }
1303 *
1304 * const emp: Employee = {
1305 * company: { address: { street: { name: "high street" } } }
1306 * }
1307 *
1308 * Option.some(emp).pipe(
1309 * Option.flatMapNullishOr((e) => e.company?.address?.street?.name)
1310 * ) // => Option.some("high street")
1311 * ```
1312 *
1313 * @see {@link flatMap} when the function already returns `Option`
1314 * @see {@link fromNullishOr} for single-value conversion
1315 *
1316 * @category sequencing
1317 * @since 4.0.0
1318 */
1319export const flatMapNullishOr: {
1320 <A, B>(f: (a: A) => B): (self: Option<A>) => Option<NonNullable<B>>
1321 <A, B>(self: Option<A>, f: (a: A) => B): Option<NonNullable<B>>
1322} = dual(
1323 2,
1324 <A, B>(self: Option<A>, f: (a: A) => B): Option<NonNullable<B>> =>
1325 isNone(self) ? none() : fromNullishOr(f(self.value))
1326)
1327
1328/**
1329 * Flattens a nested `Option<Option<A>>` into `Option<A>`.
1330 *
1331 * **When to use**
1332 *
1333 * Use when you need to remove one layer of nested `Option`.
1334 *
1335 * **Details**
1336 *
1337 * - `Some(Some(value))` → `Some(value)`
1338 * - `Some(None)` → `None`
1339 * - `None` → `None`
1340 *
1341 * **Example** (Flattening nested Options)
1342 *
1343 * ```ts import.meta.vitest
1344 * import { Option } from "effect"
1345 *
1346 * Option.flatten(Option.some(Option.some("value"))) // => Option.some("value")
1347 * Option.flatten(Option.some(Option.none())) // => Option.none()
1348 * ```
1349 *
1350 * @see {@link flatMap} which is `map` + `flatten`
1351 *
1352 * @category sequencing
1353 * @since 2.0.0
1354 */
1355export const flatten: <A>(self: Option<Option<A>>) => Option<A> = flatMap(identity)
1356
1357/**
1358 * Sequences two `Option`s, keeping the value from the second if both are `Some`.
1359 *
1360 * **When to use**
1361 *
1362 * Use when you need two `Option` values to both be `Some`, then keep only the
1363 * second value.
1364 *
1365 * **Details**
1366 *
1367 * - Both `Some` → returns `that`
1368 * - Either `None` → returns `None`
1369 *
1370 * **Example** (Keeping the second value)
1371 *
1372 * ```ts import.meta.vitest
1373 * import { Option } from "effect"
1374 *
1375 * Option.zipRight(Option.some(1), Option.some("hello")) // => Option.some("hello")
1376 * Option.zipRight(Option.none(), Option.some("hello")) // => Option.none()
1377 * ```
1378 *
1379 * @see {@link zipLeft} to keep the first value instead
1380 * @see {@link zipWith} to combine both values
1381 *
1382 * @category zipping
1383 * @since 2.0.0
1384 */
1385export const zipRight: {
1386 <B>(that: Option<B>): <_>(self: Option<_>) => Option<B>
1387 <X, B>(self: Option<X>, that: Option<B>): Option<B>
1388} = dual(2, <X, B>(self: Option<X>, that: Option<B>): Option<B> => flatMap(self, () => that))
1389
1390/**
1391 * Sequences two `Option`s, keeping the value from the first if both are `Some`.
1392 *
1393 * **When to use**
1394 *
1395 * Use when you need two `Option` values to both be `Some`, then keep only the
1396 * first value.
1397 *
1398 * **Details**
1399 *
1400 * - Both `Some` → returns `self`
1401 * - Either `None` → returns `None`
1402 *
1403 * **Example** (Keeping the first value)
1404 *
1405 * ```ts import.meta.vitest
1406 * import { Option } from "effect"
1407 *
1408 * Option.zipLeft(Option.some("hello"), Option.some(1)) // => Option.some("hello")
1409 * Option.zipLeft(Option.some("hello"), Option.none()) // => Option.none()
1410 * ```
1411 *
1412 * @see {@link zipRight} to keep the second value instead
1413 * @see {@link zipWith} to combine both values
1414 *
1415 * @category zipping
1416 * @since 2.0.0
1417 */
1418export const zipLeft: {
1419 <_>(that: Option<_>): <A>(self: Option<A>) => Option<A>
1420 <A, X>(self: Option<A>, that: Option<X>): Option<A>
1421} = dual(2, <A, X>(self: Option<A>, that: Option<X>): Option<A> => tap(self, () => that))
1422
1423/**
1424 * Composes two `Option`-returning functions into a single function that chains
1425 * them together.
1426 *
1427 * **When to use**
1428 *
1429 * Use when you need to compose two functions that each return an `Option`, so
1430 * `None` short-circuits without calling the next function.
1431 *
1432 * **Details**
1433 *
1434 * - Calls `afb(a)`, then if `Some`, calls `bfc` with its value
1435 * - Short-circuits to `None` if either function returns `None`
1436 *
1437 * **Example** (Composing parsers)
1438 *
1439 * ```ts import.meta.vitest
1440 * import { Option } from "effect"
1441 *
1442 * const parse = (s: string): Option.Option<number> =>
1443 * isNaN(Number(s)) ? Option.none() : Option.some(Number(s))
1444 *
1445 * const double = (n: number): Option.Option<number> =>
1446 * n > 0 ? Option.some(n * 2) : Option.none()
1447 *
1448 * const parseAndDouble = Option.composeK(parse, double)
1449 *
1450 * parseAndDouble("42") // => Option.some(84)
1451 * parseAndDouble("not a number") // => Option.none()
1452 * ```
1453 *
1454 * @see {@link flatMap} for single-step chaining
1455 *
1456 * @category sequencing
1457 * @since 2.0.0
1458 */
1459export const composeK: {
1460 <B, C>(bfc: (b: B) => Option<C>): <A>(afb: (a: A) => Option<B>) => (a: A) => Option<C>
1461 <A, B, C>(afb: (a: A) => Option<B>, bfc: (b: B) => Option<C>): (a: A) => Option<C>
1462} = dual(2, <A, B, C>(afb: (a: A) => Option<B>, bfc: (b: B) => Option<C>) => (a: A): Option<C> => flatMap(afb(a), bfc))
1463
1464/**
1465 * Runs a side-effecting `Option`-returning function on the value of a `Some`,
1466 * returning the original `Option` if the function returns `Some`, or `None`
1467 * if it returns `None`.
1468 *
1469 * **When to use**
1470 *
1471 * Use to validate an `Option`'s present value without transforming it, such as
1472 * adding a side-condition check in a pipeline.
1473 *
1474 * **Details**
1475 *
1476 * - `None` → `None`
1477 * - `Some` → calls `f(value)`; if result is `Some`, returns original `self`; if `None`, returns `None`
1478 *
1479 * **Example** (Validating without transforming)
1480 *
1481 * ```ts import.meta.vitest
1482 * import { Option } from "effect"
1483 *
1484 * const getInteger = (n: number) =>
1485 * Number.isInteger(n) ? Option.some(n) : Option.none()
1486 *
1487 * Option.tap(Option.some(1), getInteger) // => Option.some(1)
1488 * Option.tap(Option.some(1.14), getInteger) // => Option.none()
1489 * ```
1490 *
1491 * @see {@link flatMap} when you want to transform the value
1492 * @see {@link filter} for predicate-based filtering
1493 *
1494 * @category sequencing
1495 * @since 2.0.0
1496 */
1497export const tap: {
1498 <A, X>(f: (a: A) => Option<X>): (self: Option<A>) => Option<A>
1499 <A, X>(self: Option<A>, f: (a: A) => Option<X>): Option<A>
1500} = dual(2, <A, X>(self: Option<A>, f: (a: A) => Option<X>): Option<A> => flatMap(self, (a) => map(f(a), () => a)))
1501
1502/**
1503 * Combines two `Option`s into a `Some` containing a tuple `[A, B]` if both
1504 * are `Some`.
1505 *
1506 * **When to use**
1507 *
1508 * Use when you need to require two `Option` values to both be `Some` and keep
1509 * both values as a tuple.
1510 *
1511 * **Details**
1512 *
1513 * - Both `Some` → `Some([a, b])`
1514 * - Either `None` → `None`
1515 *
1516 * **Example** (Pairing two Options)
1517 *
1518 * ```ts import.meta.vitest
1519 * import { Option } from "effect"
1520 *
1521 * Option.product(Option.some("hello"), Option.some(42)) // => Option.some(["hello", 42])
1522 * Option.product(Option.none(), Option.some(42)) // => Option.none()
1523 * ```
1524 *
1525 * @see {@link zipWith} to combine with a function instead of a tuple
1526 * @see {@link all} to combine many `Option`s
1527 *
1528 * @category combining
1529 * @since 2.0.0
1530 */
1531export const product: {
1532 <B>(that: Option<B>): <A>(self: Option<A>) => Option<[A, B]>
1533 <A, B>(self: Option<A>, that: Option<B>): Option<[A, B]>
1534} = dual(
1535 2,
1536 <A, B>(self: Option<A>, that: Option<B>): Option<[A, B]> =>
1537 isSome(self) && isSome(that) ? some([self.value, that.value]) : none()
1538)
1539
1540/**
1541 * Combines a primary `Option` with an iterable of `Option`s into a tuple if
1542 * all are `Some`.
1543 *
1544 * **When to use**
1545 *
1546 * Use when you need several `Option` values of the same type to all be `Some`
1547 * and return them as a non-empty tuple.
1548 *
1549 * **Details**
1550 *
1551 * - All `Some` → `Some([self.value, ...rest])`
1552 * - Any `None` → `None`
1553 *
1554 * **Example** (Combining many Options)
1555 *
1556 * ```ts import.meta.vitest
1557 * import { Option } from "effect"
1558 *
1559 * const first = Option.some(1)
1560 * const rest = [Option.some(2), Option.some(3)]
1561 *
1562 * Option.productMany(first, rest) // => Option.some([1, 2, 3])
1563 * Option.productMany(first, [Option.some(2), Option.none()]) // => Option.none()
1564 * ```
1565 *
1566 * @see {@link product} for combining exactly two
1567 * @see {@link all} for tuples, structs, and iterables
1568 *
1569 * @category combining
1570 * @since 2.0.0
1571 */
1572export const productMany: {
1573 <A>(collection: Iterable<Option<A>>): (self: Option<A>) => Option<[A, ...Array<A>]>
1574 <A>(self: Option<A>, collection: Iterable<Option<A>>): Option<[A, ...Array<A>]>
1575} = dual(2, <A>(self: Option<A>, collection: Iterable<Option<A>>): Option<[A, ...Array<A>]> => {
1576 if (isNone(self)) {
1577 return none()
1578 }
1579 const out: [A, ...Array<A>] = [self.value]
1580 for (const o of collection) {
1581 if (isNone(o)) {
1582 return none()
1583 }
1584 out.push(o.value)
1585 }
1586 return some(out)
1587})
1588
1589/**
1590 * Combines a structure of `Option`s (tuple, struct, or iterable) into a single
1591 * `Option` containing the unwrapped structure.
1592 *
1593 * **When to use**
1594 *
1595 * Use when you need to combine multiple `Option` values into one while
1596 * preserving the input shape, with any `None` making the result `None`.
1597 *
1598 * **Details**
1599 *
1600 * - Tuple input → `Option` of a tuple with the same length
1601 * - Struct input → `Option` of a struct with the same keys
1602 * - Iterable input → `Option` of an `Array`
1603 * - Any `None` in the input → entire result is `None`
1604 *
1605 * **Example** (Combining a tuple and a struct)
1606 *
1607 * ```ts import.meta.vitest
1608 * import { Option } from "effect"
1609 *
1610 * const maybeName: Option.Option<string> = Option.some("John")
1611 * const maybeAge: Option.Option<number> = Option.some(25)
1612 *
1613 * // ┌─── Option<[string, number]>
1614 * // ▼
1615 * const tuple = Option.all([maybeName, maybeAge]) // => Option.some(["John", 25])
1616 *
1617 * // ┌─── Option<{ name: string; age: number; }>
1618 * // ▼
1619 * const struct = Option.all({ name: maybeName, age: maybeAge }) // => Option.some({ name: "John", age: 25 })
1620 * ```
1621 *
1622 * @see {@link product} for combining exactly two
1623 * @see {@link productMany} for a homogeneous collection
1624 *
1625 * @category combining
1626 * @since 2.0.0
1627 */
1628// @ts-expect-error
1629export const all: <const I extends Iterable<Option<any>> | Record<string, Option<any>>>(
1630 input: I
1631) => [I] extends [ReadonlyArray<Option<any>>] ? Option<
1632 { -readonly [K in keyof I]: [I[K]] extends [Option<infer A>] ? A : never }
1633 >
1634 : [I] extends [Iterable<Option<infer A>>] ? Option<Array<A>>
1635 : Option<{ -readonly [K in keyof I]: [I[K]] extends [Option<infer A>] ? A : never }> = (
1636 input: Iterable<Option<any>> | Record<string, Option<any>>
1637 ): Option<any> => {
1638 if (Symbol.iterator in input) {
1639 const out: Array<Option<any>> = []
1640 for (const o of (input as Iterable<Option<any>>)) {
1641 if (isNone(o)) {
1642 return none()
1643 }
1644 out.push(o.value)
1645 }
1646 return some(out)
1647 }
1648
1649 const out: Record<string, any> = {}
1650 for (const key of Object.keys(input)) {
1651 const o = input[key]
1652 if (isNone(o)) {
1653 return none()
1654 }
1655 InternalRecord.assignProperty(out, key, o.value)
1656 }
1657 return some(out)
1658 }
1659
1660/**
1661 * Combines two `Option`s using a provided function.
1662 *
1663 * **When to use**
1664 *
1665 * Use when you need to combine two present `Option` values into a computed
1666 * result.
1667 *
1668 * **Details**
1669 *
1670 * - Both `Some` → applies `f(a, b)` and wraps in `Some`
1671 * - Either `None` → `None`
1672 *
1673 * **Example** (Combining with a function)
1674 *
1675 * ```ts import.meta.vitest
1676 * import { Option } from "effect"
1677 *
1678 * Option.zipWith(
1679 * Option.some("John"),
1680 * Option.some(25),
1681 * (name, age) => ({ name: name.toUpperCase(), age })
1682 * ) // => Option.some({ name: "JOHN", age: 25 })
1683 * ```
1684 *
1685 * @see {@link product} to combine into a tuple instead
1686 * @see {@link lift2} to lift a binary function
1687 *
1688 * @category zipping
1689 * @since 2.0.0
1690 */
1691export const zipWith: {
1692 <B, A, C>(that: Option<B>, f: (a: A, b: B) => C): (self: Option<A>) => Option<C>
1693 <A, B, C>(self: Option<A>, that: Option<B>, f: (a: A, b: B) => C): Option<C>
1694} = dual(
1695 3,
1696 <A, B, C>(self: Option<A>, that: Option<B>, f: (a: A, b: B) => C): Option<C> =>
1697 map(product(self, that), ([a, b]) => f(a, b))
1698)
1699
1700/**
1701 * Reduces an iterable of `Option`s to a single value, skipping `None` entries.
1702 *
1703 * **When to use**
1704 *
1705 * Use when you need to aggregate values from a collection where some may be
1706 * absent.
1707 *
1708 * **Details**
1709 *
1710 * - Iterates through the collection, applying `f` only to `Some` values
1711 * - `None` values are skipped entirely
1712 * - Returns the accumulated result
1713 *
1714 * **Example** (Summing present values)
1715 *
1716 * ```ts import.meta.vitest
1717 * import { Option, pipe } from "effect"
1718 *
1719 * const items = [Option.some(1), Option.none(), Option.some(2), Option.none()]
1720 *
1721 * pipe(items, Option.reduceCompact(0, (b, a) => b + a)) // => 3
1722 * ```
1723 *
1724 * @category folding
1725 * @since 2.0.0
1726 */
1727export const reduceCompact: {
1728 <B, A>(b: B, f: (b: B, a: A) => B): (self: Iterable<Option<A>>) => B
1729 <A, B>(self: Iterable<Option<A>>, b: B, f: (b: B, a: A) => B): B
1730} = dual(
1731 3,
1732 <A, B>(self: Iterable<Option<A>>, b: B, f: (b: B, a: A) => B): B => {
1733 let out: B = b
1734 for (const oa of self) {
1735 if (isSome(oa)) {
1736 out = f(out, oa.value)
1737 }
1738 }
1739 return out
1740 }
1741)
1742
1743/**
1744 * Converts an `Option` into an `Array`.
1745 *
1746 * **When to use**
1747 *
1748 * Use when you need to pass an `Option` to array-based APIs or spread optional
1749 * values into collections.
1750 *
1751 * **Details**
1752 *
1753 * - `Some` → single-element array `[value]`
1754 * - `None` → empty array `[]`
1755 *
1756 * **Example** (Converting to an array)
1757 *
1758 * ```ts import.meta.vitest
1759 * import { Option } from "effect"
1760 *
1761 * Option.toArray(Option.some(1)) // => [1]
1762 * Option.toArray(Option.none()) // => []
1763 * ```
1764 *
1765 * @see {@link fromIterable} for the inverse direction
1766 *
1767 * @category converting
1768 * @since 2.0.0
1769 */
1770export const toArray = <A>(self: Option<A>): Array<A> => isNone(self) ? [] : [self.value]
1771
1772/**
1773 * Splits an `Option` into two `Option`s using a function that returns a `Result`.
1774 *
1775 * **When to use**
1776 *
1777 * Use when you need to split an optional value into success and failure
1778 * channels using a `Result`-returning function.
1779 *
1780 * **Details**
1781 *
1782 * - `None` → `[None, None]`
1783 * - `Some` where `f` returns `Ok` → `[Some(value), None]`
1784 * - `Some` where `f` returns `Err` → `[None, Some(error)]`
1785 *
1786 * **Example** (Partitioning by Result)
1787 *
1788 * ```ts import.meta.vitest
1789 * import { Option, Result } from "effect"
1790 *
1791 * const parseNumber = (s: string): Result.Result<number, string> => {
1792 * const n = Number(s)
1793 * return isNaN(n) ? Result.fail("Not a number") : Result.succeed(n)
1794 * }
1795 *
1796 * Option.partitionMap(Option.some("42"), parseNumber) // => [Option.some(42), Option.none()]
1797 * Option.partitionMap(Option.some("abc"), parseNumber) // => [Option.none(), Option.some("Not a number")]
1798 * Option.partitionMap(Option.none(), parseNumber) // => [Option.none(), Option.none()]
1799 * ```
1800 *
1801 * @see {@link filter} for simple predicate-based filtering
1802 *
1803 * @category filtering
1804 * @since 2.0.0
1805 */
1806export const partitionMap: {
1807 <A, B, C>(f: (a: A) => Result<C, B>): (self: Option<A>) => [passes: Option<C>, fails: Option<B>]
1808 <A, B, C>(self: Option<A>, f: (a: A) => Result<C, B>): [passes: Option<C>, fails: Option<B>]
1809} = dual(2, <A, B, C>(
1810 self: Option<A>,
1811 f: (a: A) => Result<C, B>
1812): [passes: Option<C>, fails: Option<B>] => {
1813 if (isNone(self)) {
1814 return [none(), none()]
1815 }
1816 const e = f(self.value)
1817 return result.isFailure(e) ? [none(), some(e.failure)] : [some(e.success), none()]
1818})
1819
1820/**
1821 * Transforms and filters an `Option` using a `Filter` callback.
1822 *
1823 * **When to use**
1824 *
1825 * Use to transform an `Option`'s present value and discard it when the `Filter`
1826 * fails.
1827 *
1828 * **Details**
1829 *
1830 * The callback returns a `Result`: `Result.succeed` keeps and transforms the
1831 * value, while `Result.fail` discards it.
1832 *
1833 * **Example** (Filtering and transforming)
1834 *
1835 * ```ts import.meta.vitest
1836 * import { Option, Result } from "effect"
1837 *
1838 * Option.filterMap(
1839 * Option.some(2),
1840 * (n) => (n % 2 === 0 ? Result.succeed(`Even: ${n}`) : Result.failVoid)
1841 * ) // => Option.some("Even: 2")
1842 * ```
1843 *
1844 * @see {@link filter} for predicate-based filtering
1845 *
1846 * @category filtering
1847 * @since 2.0.0
1848 */
1849export const filterMap: {
1850 <A, B, X>(f: Filter.Filter<A, B, X>): (self: Option<A>) => Option<B>
1851 <A, B, X>(self: Option<A>, f: Filter.Filter<A, B, X>): Option<B>
1852} = dual(2, <A, B, X>(self: Option<A>, f: Filter.Filter<A, B, X>): Option<B> => {
1853 if (isNone(self)) {
1854 return none()
1855 }
1856 const next = f(self.value)
1857 return result.isSuccess(next) ? some(next.success) : none()
1858})
1859
1860/**
1861 * Filters an `Option` using a predicate. Returns `None` if the predicate is
1862 * not satisfied or the input is `None`.
1863 *
1864 * **When to use**
1865 *
1866 * Use when you need to discard an `Option`'s present value when it does not
1867 * meet a condition, while narrowing the type via a refinement predicate.
1868 *
1869 * **Details**
1870 *
1871 * - `None` → `None`
1872 * - `Some` where `predicate(value)` is `true` → `Some(value)`
1873 * - `Some` where `predicate(value)` is `false` → `None`
1874 * - Supports refinements for type narrowing
1875 *
1876 * **Example** (Filtering with a predicate)
1877 *
1878 * ```ts import.meta.vitest
1879 * import { Option } from "effect"
1880 *
1881 * const removeEmpty = (input: Option.Option<string>) =>
1882 * Option.filter(input, (value) => value !== "")
1883 *
1884 * removeEmpty(Option.some("hello")) // => Option.some("hello")
1885 * removeEmpty(Option.some("")) // => Option.none()
1886 * removeEmpty(Option.none()) // => Option.none()
1887 * ```
1888 *
1889 * @see {@link filterMap} to transform and filter simultaneously
1890 * @see {@link exists} to test without filtering
1891 *
1892 * @category filtering
1893 * @since 2.0.0
1894 */
1895export const filter: {
1896 <A, B extends A>(refinement: Refinement<A, B>): (self: Option<A>) => Option<B>
1897 <A>(predicate: Predicate<A>): <B extends A>(self: Option<B>) => Option<B>
1898 <A, B extends A>(self: Option<A>, refinement: Refinement<A, B>): Option<B>
1899 <A>(self: Option<A>, predicate: Predicate<A>): Option<A>
1900} = dual(
1901 2,
1902 <A>(self: Option<A>, predicate: Predicate<A>): Option<A> =>
1903 isNone(self) ? none() : predicate(self.value) ? some(self.value) : none()
1904)
1905
1906/**
1907 * Creates an `Equivalence` for `Option<A>` from an `Equivalence` for `A`.
1908 *
1909 * **When to use**
1910 *
1911 * Use when you need equality to treat two `None` values as equal and compare
1912 * two `Some` values with a supplied equality rule.
1913 *
1914 * **Details**
1915 *
1916 * - `None` vs `None` → `true`
1917 * - `Some` vs `None` (or vice versa) → `false`
1918 * - `Some(a)` vs `Some(b)` → delegates to the provided `Equivalence`
1919 *
1920 * **Example** (Comparing Options)
1921 *
1922 * ```ts import.meta.vitest
1923 * import { Equivalence, Option } from "effect"
1924 *
1925 * const eq = Option.makeEquivalence(Equivalence.strictEqual<number>())
1926 *
1927 * eq(Option.some(1), Option.some(1)) // => true
1928 * eq(Option.some(1), Option.some(2)) // => false
1929 * eq(Option.none(), Option.none()) // => true
1930 * ```
1931 *
1932 * @category instances
1933 * @since 4.0.0
1934 */
1935export const makeEquivalence = <A>(isEquivalent: Equivalence.Equivalence<A>): Equivalence.Equivalence<Option<A>> =>
1936 Equivalence.make((x, y) => isNone(x) ? isNone(y) : isNone(y) ? false : isEquivalent(x.value, y.value))
1937
1938/**
1939 * Creates an `Order` for `Option<A>` from an `Order` for `A`.
1940 *
1941 * **When to use**
1942 *
1943 * Use when you need to sort `Some` and `None` values, with `None` ordered
1944 * before present values and present values compared by a supplied ordering
1945 * rule.
1946 *
1947 * **Details**
1948 *
1949 * - `None` is considered less than any `Some`
1950 * - Two `Some` values are compared using the provided `Order`
1951 * - Two `None` values are equal (returns `0`)
1952 *
1953 * **Example** (Ordering Options)
1954 *
1955 * ```ts import.meta.vitest
1956 * import { Number as N, Option } from "effect"
1957 *
1958 * const ord = Option.makeOrder(N.Order)
1959 *
1960 * ord(Option.none(), Option.some(1)) // => -1
1961 * ord(Option.some(1), Option.none()) // => 1
1962 * ord(Option.some(1), Option.some(2)) // => -1
1963 * ```
1964 *
1965 * @category sorting
1966 * @since 4.0.0
1967 */
1968export const makeOrder = <A>(O: Order<A>): Order<Option<A>> =>
1969 order.make((self, that) => isSome(self) ? (isSome(that) ? O(self.value, that.value) : 1) : -1)
1970
1971/**
1972 * Lifts a binary function to operate on two `Option` values.
1973 *
1974 * **When to use**
1975 *
1976 * Use when you need to reuse an existing binary function with two `Option`
1977 * values.
1978 *
1979 * **Details**
1980 *
1981 * - Both `Some` → applies `f` and wraps in `Some`
1982 * - Either `None` → `None`
1983 *
1984 * **Example** (Lifting addition)
1985 *
1986 * ```ts import.meta.vitest
1987 * import { Option } from "effect"
1988 *
1989 * const addOptions = Option.lift2((a: number, b: number) => a + b)
1990 *
1991 * addOptions(Option.some(2), Option.some(3)) // => Option.some(5)
1992 * addOptions(Option.some(2), Option.none()) // => Option.none()
1993 * ```
1994 *
1995 * @see {@link zipWith} for a non-lifted variant
1996 *
1997 * @category lifting
1998 * @since 2.0.0
1999 */
2000export const lift2 = <A, B, C>(f: (a: A, b: B) => C): {
2001 (that: Option<B>): (self: Option<A>) => Option<C>
2002 (self: Option<A>, that: Option<B>): Option<C>
2003} => dual(2, (self: Option<A>, that: Option<B>): Option<C> => zipWith(self, that, f))
2004
2005/**
2006 * Lifts a `Predicate` or `Refinement` into the `Option` context: returns
2007 * `Some(value)` when the predicate holds, `None` otherwise.
2008 *
2009 * **When to use**
2010 *
2011 * Use to convert a boolean check into an `Option`-returning function
2012 * - Validating input and wrapping it in `Option`
2013 *
2014 * **Details**
2015 *
2016 * - `predicate(value)` is `true` → `Some(value)`
2017 * - `predicate(value)` is `false` → `None`
2018 * - Supports refinements for type narrowing
2019 *
2020 * **Example** (Validating positive numbers)
2021 *
2022 * ```ts import.meta.vitest
2023 * import { Option } from "effect"
2024 *
2025 * const parsePositive = Option.liftPredicate((n: number) => n > 0)
2026 *
2027 * parsePositive(1) // => Option.some(1)
2028 * parsePositive(-1) // => Option.none()
2029 * ```
2030 *
2031 * @see {@link filter} to apply a predicate to an existing `Option`
2032 * @see {@link toRefinement} for the inverse direction
2033 *
2034 * @category lifting
2035 * @since 2.0.0
2036 */
2037export const liftPredicate: { // Note: I intentionally avoid using the NoInfer pattern here.
2038 <A, B extends A>(refinement: Refinement<A, B>): (a: A) => Option<B>
2039 <B extends A, A = B>(predicate: Predicate<A>): (b: B) => Option<B>
2040 <A, B extends A>(
2041 self: A,
2042 refinement: Refinement<A, B>
2043 ): Option<B>
2044 <B extends A, A = B>(
2045 self: B,
2046 predicate: Predicate<A>
2047 ): Option<B>
2048} = dual(
2049 2,
2050 <B extends A, A = B>(b: B, predicate: Predicate<A>): Option<B> => predicate(b) ? some(b) : none()
2051)
2052
2053/**
2054 * Checks whether an `Option` contains a value equivalent to the given one, using a
2055 * custom `Equivalence`.
2056 *
2057 * **When to use**
2058 *
2059 * Use when you need to test whether an `Option` contains a value using a
2060 * custom equality check.
2061 *
2062 * **Details**
2063 *
2064 * - `Some` where `isEquivalent(value, a)` is `true` → `true`
2065 * - `Some` where not equivalent, or `None` → `false`
2066 *
2067 * **Example** (Checking with custom equivalence)
2068 *
2069 * ```ts import.meta.vitest
2070 * import { Equivalence, Option } from "effect"
2071 *
2072 * const check = Option.containsWith(Equivalence.strictEqual<number>())
2073 *
2074 * Option.some(2).pipe(check(2)) // => true
2075 * Option.some(1).pipe(check(2)) // => false
2076 * Option.none().pipe(check(2)) // => false
2077 * ```
2078 *
2079 * @see {@link contains} for a version using default equality
2080 *
2081 * @category predicates
2082 * @since 2.0.0
2083 */
2084export const containsWith = <A>(isEquivalent: (self: A, that: A) => boolean): {
2085 (a: A): (self: Option<A>) => boolean
2086 (self: Option<A>, a: A): boolean
2087} => dual(2, (self: Option<A>, a: A): boolean => isNone(self) ? false : isEquivalent(self.value, a))
2088
2089/**
2090 * Checks whether an `Option` contains a value equal to the given one, using default
2091 * structural equality.
2092 *
2093 * **When to use**
2094 *
2095 * Use when you need a quick membership test for an `Option` value using
2096 * standard equality.
2097 *
2098 * **Details**
2099 *
2100 * - `Some` where `Equal.equals(value, a)` is `true` → `true`
2101 * - `Some` where not equal, or `None` → `false`
2102 *
2103 * **Example** (Checking containment)
2104 *
2105 * ```ts import.meta.vitest
2106 * import { Option } from "effect"
2107 *
2108 * Option.some(2).pipe(Option.contains(2)) // => true
2109 * Option.some(1).pipe(Option.contains(2)) // => false
2110 * Option.none().pipe(Option.contains(2)) // => false
2111 * ```
2112 *
2113 * @see {@link containsWith} for custom equality
2114 * @see {@link exists} to test with a predicate
2115 *
2116 * @category predicates
2117 * @since 2.0.0
2118 */
2119export const contains: {
2120 <A>(a: A): (self: Option<A>) => boolean
2121 <A>(self: Option<A>, a: A): boolean
2122} = containsWith(Equal.asEquivalence())
2123
2124/**
2125 * Checks whether the value in a `Some` satisfies a predicate or refinement.
2126 *
2127 * **When to use**
2128 *
2129 * Use to check a condition on an optional value without unwrapping
2130 *
2131 * **Details**
2132 *
2133 * - `None` → `false`
2134 * - `Some` where `predicate(value)` is `true` → `true`
2135 * - `Some` where `predicate(value)` is `false` → `false`
2136 * - With a refinement, narrows the `Option` type on `true`
2137 *
2138 * **Example** (Testing a condition)
2139 *
2140 * ```ts import.meta.vitest
2141 * import { Option } from "effect"
2142 *
2143 * const isEven = (n: number) => n % 2 === 0
2144 *
2145 * Option.some(2).pipe(Option.exists(isEven)) // => true
2146 * Option.some(1).pipe(Option.exists(isEven)) // => false
2147 * Option.none().pipe(Option.exists(isEven)) // => false
2148 * ```
2149 *
2150 * @see {@link filter} to keep or discard based on a predicate
2151 * @see {@link contains} to test for a specific value
2152 *
2153 * @category predicates
2154 * @since 2.0.0
2155 */
2156export const exists: {
2157 <A, B extends A>(refinement: Refinement<NoInfer<A>, B>): (self: Option<A>) => self is Option<B>
2158 <A>(predicate: Predicate<NoInfer<A>>): (self: Option<A>) => boolean
2159 <A, B extends A>(self: Option<A>, refinement: Refinement<A, B>): self is Option<B>
2160 <A>(self: Option<A>, predicate: Predicate<A>): boolean
2161} = dual(
2162 2,
2163 <A, B extends A>(self: Option<A>, refinement: Refinement<A, B>): self is Option<B> =>
2164 isNone(self) ? false : refinement(self.value)
2165)
2166
2167// -------------------------------------------------------------------------------------
2168// do notation
2169// -------------------------------------------------------------------------------------
2170
2171/**
2172 * Gives a name to the value of an `Option`, creating a single-key record
2173 * inside `Some`. Starting point for the do notation pipeline.
2174 *
2175 * **When to use**
2176 *
2177 * Use when you need to start an `Option` do notation chain by naming the first
2178 * value.
2179 *
2180 * **Example** (Starting do notation)
2181 *
2182 * ```ts import.meta.vitest
2183 * import { Option, pipe } from "effect"
2184 *
2185 * pipe(
2186 * Option.some(2),
2187 * Option.bindTo("x"),
2188 * Option.bind("y", () => Option.some(3)),
2189 * Option.let("sum", ({ x, y }) => x + y)
2190 * ) // => Option.some({ x: 2, y: 3, sum: 5 })
2191 * ```
2192 *
2193 * @see {@link Do} for starting with an empty record
2194 * @see {@link bind} to add `Option` values
2195 * @see {@link let_ let} to add plain values
2196 *
2197 * @category mapping
2198 * @since 2.0.0
2199 */
2200export const bindTo: {
2201 <N extends string>(name: N): <A>(self: Option<A>) => Option<{ [K in N]: A }>
2202 <A, N extends string>(self: Option<A>, name: N): Option<{ [K in N]: A }>
2203} = doNotation.bindTo<OptionTypeLambda>(map)
2204
2205const let_: {
2206 <N extends string, A extends object, B>(
2207 name: Exclude<N, keyof A>,
2208 f: (a: NoInfer<A>) => B
2209 ): (self: Option<A>) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }>
2210 <A extends object, N extends string, B>(
2211 self: Option<A>,
2212 name: Exclude<N, keyof A>,
2213 f: (a: NoInfer<A>) => B
2214 ): Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }>
2215} = doNotation.let_<OptionTypeLambda>(map)
2216
2217export {
2218 /**
2219 * Adds a computed plain value to the do notation record.
2220 *
2221 * **When to use**
2222 *
2223 * Use when you need to bind a derived non-`Option` value in an `Option` do
2224 * notation pipeline.
2225 *
2226 * **Example** (Adding a computed value)
2227 *
2228 * ```ts import.meta.vitest
2229 * import { Option, pipe } from "effect"
2230 *
2231 * pipe(
2232 * Option.Do,
2233 * Option.bind("x", () => Option.some(2)),
2234 * Option.bind("y", () => Option.some(3)),
2235 * Option.let("sum", ({ x, y }) => x + y)
2236 * ) // => Option.some({ x: 2, y: 3, sum: 5 })
2237 * ```
2238 *
2239 * @see {@link Do} for starting the chain
2240 * @see {@link bind} to add `Option` values
2241 * @see {@link bindTo} to start by naming an existing `Option`
2242 *
2243 * @category mapping
2244 * @since 2.0.0
2245 */
2246 let_ as let
2247}
2248
2249/**
2250 * Adds an `Option` value to the do notation record under a given name. If the
2251 * `Option` is `None`, the whole pipeline short-circuits to `None`.
2252 *
2253 * **When to use**
2254 *
2255 * Use when you need to sequence `Option` computations in do notation.
2256 *
2257 * **Example** (Binding Option values)
2258 *
2259 * ```ts import.meta.vitest
2260 * import { Option, pipe } from "effect"
2261 *
2262 * pipe(
2263 * Option.Do,
2264 * Option.bind("x", () => Option.some(2)),
2265 * Option.bind("y", () => Option.some(3)),
2266 * Option.let("sum", ({ x, y }) => x + y),
2267 * Option.filter(({ x, y }) => x * y > 5)
2268 * ) // => Option.some({ x: 2, y: 3, sum: 5 })
2269 * ```
2270 *
2271 * @see {@link Do} for starting the chain
2272 * @see {@link let_ let} to add plain values
2273 * @see {@link bindTo} to start by naming an existing `Option`
2274 *
2275 * @category sequencing
2276 * @since 2.0.0
2277 */
2278export const bind: {
2279 <N extends string, A extends object, B>(
2280 name: Exclude<N, keyof A>,
2281 f: (a: NoInfer<A>) => Option<B>
2282 ): (self: Option<A>) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }>
2283 <A extends object, N extends string, B>(
2284 self: Option<A>,
2285 name: Exclude<N, keyof A>,
2286 f: (a: NoInfer<A>) => Option<B>
2287 ): Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }>
2288} = doNotation.bind<OptionTypeLambda>(map, flatMap)
2289
2290/**
2291 * Provides an `Option` containing an empty record `{}`, used as the starting point for
2292 * do notation chains.
2293 *
2294 * **When to use**
2295 *
2296 * Use when you need to start an `Option` do notation pipeline before adding
2297 * bindings.
2298 *
2299 * **Example** (Building Option pipelines with do notation)
2300 *
2301 * ```ts import.meta.vitest
2302 * import { Option, pipe } from "effect"
2303 *
2304 * pipe(
2305 * Option.Do,
2306 * Option.bind("x", () => Option.some(2)),
2307 * Option.bind("y", () => Option.some(3)),
2308 * Option.let("sum", ({ x, y }) => x + y),
2309 * Option.filter(({ x, y }) => x * y > 5)
2310 * ) // => Option.some({ x: 2, y: 3, sum: 5 })
2311 * ```
2312 *
2313 * @see {@link bind} to add `Option` values
2314 * @see {@link let_ let} to add plain values
2315 * @see {@link bindTo} to start by naming an existing `Option`
2316 *
2317 * @category constructors
2318 * @since 2.0.0
2319 */
2320export const Do: Option<{}> = some({})
2321
2322/**
2323 * Provides generator-based syntax for `Option`, similar to `async`/`await` but for
2324 * optional values. Yielding a `None` short-circuits the generator to `None`.
2325 *
2326 * **When to use**
2327 *
2328 * Use when you need generator syntax for a sequence of `Option` steps that
2329 * should short-circuit on `None`.
2330 *
2331 * **Details**
2332 *
2333 * - Each `yield*` unwraps a `Some` value or short-circuits to `None`
2334 * - The return value is wrapped in `Some`
2335 * - No `Effect` runtime is needed
2336 *
2337 * **Example** (Sequencing Option computations with generator syntax)
2338 *
2339 * ```ts import.meta.vitest
2340 * import { Option } from "effect"
2341 *
2342 * const maybeName: Option.Option<string> = Option.some("John")
2343 * const maybeAge: Option.Option<number> = Option.some(25)
2344 *
2345 * Option.gen(function*() {
2346 * const name = (yield* maybeName).toUpperCase()
2347 * const age = yield* maybeAge
2348 * return { name, age }
2349 * }) // => Option.some({ name: "JOHN", age: 25 })
2350 * ```
2351 *
2352 * @see {@link Do} / {@link bind} for the do notation alternative
2353 *
2354 * @category generators
2355 * @since 2.0.0
2356 */
2357export const gen: Gen.Gen<OptionTypeLambda> = (...args) => {
2358 const f = args.length === 1 ? args[0] : args[1].bind(args[0])
2359 const iterator = f()
2360 let state: IteratorResult<any> = iterator.next()
2361 while (!state.done) {
2362 const current = state.value
2363 if (isNone(current)) {
2364 return current
2365 }
2366 state = iterator.next(current.value as never)
2367 }
2368 return some(state.value)
2369}
2370
2371/**
2372 * Creates a `Reducer` for `Option<A>` that prioritizes the first non-`None`
2373 * value and combines values when both are `Some`.
2374 *
2375 * **When to use**
2376 *
2377 * Use to build an `Option` reducer that falls back to the first available value
2378 * when either side may be absent.
2379 *
2380 * **Details**
2381 *
2382 * - `None` + `None` → `None`
2383 * - `Some(a)` + `None` → `Some(a)`
2384 * - `None` + `Some(b)` → `Some(b)`
2385 * - `Some(a)` + `Some(b)` → `Some(combine(a, b))`
2386 * - Initial value is `None`
2387 *
2388 * **Example** (Reducing with first-wins semantics)
2389 *
2390 * ```ts import.meta.vitest
2391 * import { Number, Option } from "effect"
2392 *
2393 * const reducer = Option.makeReducer(Number.ReducerSum)
2394 * reducer.combineAll([Option.some(1), Option.none(), Option.some(2)]) // => Option.some(3)
2395 * ```
2396 *
2397 * @see {@link makeReducerFailFast} for fail-fast semantics
2398 *
2399 * @category constructors
2400 * @since 4.0.0
2401 */
2402export function makeReducer<A>(combiner: Combiner.Combiner<A>): Reducer.Reducer<Option<A>> {
2403 return Reducer.make((self, that) => {
2404 if (isNone(self)) return that
2405 if (isNone(that)) return self
2406 return some(combiner.combine(self.value, that.value))
2407 }, none())
2408}
2409
2410/**
2411 * Creates a `Combiner` for `Option<A>` with fail-fast semantics: returns `None`
2412 * if either operand is `None`.
2413 *
2414 * **When to use**
2415 *
2416 * Use when you need an `Option` combiner that returns `None` unless both
2417 * operands are `Some`.
2418 *
2419 * **Details**
2420 *
2421 * - `None` + anything → `None`
2422 * - anything + `None` → `None`
2423 * - `Some(a)` + `Some(b)` → `Some(combine(a, b))`
2424 *
2425 * **Example** (Fail-fast combining)
2426 *
2427 * ```ts import.meta.vitest
2428 * import { Number, Option } from "effect"
2429 *
2430 * const combiner = Option.makeCombinerFailFast(Number.ReducerSum)
2431 * combiner.combine(Option.some(1), Option.some(2)) // => Option.some(3)
2432 * combiner.combine(Option.some(1), Option.none()) // => Option.none()
2433 * ```
2434 *
2435 * @see {@link makeReducerFailFast} to get a full `Reducer`
2436 *
2437 * @category constructors
2438 * @since 4.0.0
2439 */
2440export function makeCombinerFailFast<A>(combiner: Combiner.Combiner<A>): Combiner.Combiner<Option<A>> {
2441 return Combiner.make((self, that) => {
2442 if (isNone(self) || isNone(that)) return none()
2443 return some(combiner.combine(self.value, that.value))
2444 })
2445}
2446
2447/**
2448 * Creates a `Reducer` for `Option<A>` by lifting an existing `Reducer` with
2449 * fail-fast semantics.
2450 *
2451 * **When to use**
2452 *
2453 * Use when you need to reduce `Option` values with fail-fast semantics, where
2454 * any `None` aborts the entire result instead of being skipped.
2455 *
2456 * **Details**
2457 *
2458 * - Initial value is `Some(reducer.initialValue)`
2459 * - Combines only when both operands are `Some`
2460 * - Any `None` causes the result to become `None` immediately
2461 *
2462 * **Example** (Fail-fast reducing)
2463 *
2464 * ```ts import.meta.vitest
2465 * import { Number, Option } from "effect"
2466 *
2467 * const reducer = Option.makeReducerFailFast(Number.ReducerSum)
2468 * reducer.combineAll([Option.some(1), Option.some(2)]) // => Option.some(3)
2469 * reducer.combineAll([Option.some(1), Option.none()]) // => Option.none()
2470 * ```
2471 *
2472 * @see {@link makeCombinerFailFast} for just the combiner
2473 * @see {@link makeReducer} for non-fail-fast semantics
2474 *
2475 * @category constructors
2476 * @since 4.0.0
2477 */
2478export function makeReducerFailFast<A>(reducer: Reducer.Reducer<A>): Reducer.Reducer<Option<A>> {
2479 const combine = makeCombinerFailFast(reducer).combine
2480 const initialValue = some(reducer.initialValue)
2481 return Reducer.make(combine, initialValue, (collection) => {
2482 let out = initialValue
2483 for (const value of collection) {
2484 out = combine(out, value)
2485 if (isNone(out)) return out
2486 }
2487 return out
2488 })
2489}