1/**
2 * Builds pattern matchers for TypeScript values.
3 *
4 * `Match` lets you add ordered cases and then finish them with a result,
5 * fallback, `Option`, or exhaustive check. Use `Match.type` to define a
6 * reusable matcher for a type, or `Match.value` to match one value immediately.
7 * Cases can match literal values, predicates, object shapes, tags, negated
8 * patterns, and common checks such as strings, numbers, records, and class
9 * instances.
10 *
11 * @since 4.0.0
12 */
13import * as internal from "./internal/matcher.ts"
14import type * as Option from "./Option.ts"
15import type { Pipeable } from "./Pipeable.ts"
16import * as Predicate from "./Predicate.ts"
17import type * as Result from "./Result.ts"
18import type * as T from "./Types.ts"
19import type { Unify } from "./Unify.ts"
20
21const TypeId = internal.TypeId
22
23// The conditional must stay deferred until P is inferred. Replacing it with an
24// intersection loses contextual typing for nested generic calls (microsoft/TypeScript#52864).
25type Contextual<P, Fallback> = [P] extends [never] ? Fallback : P
26
27type TagHandlers<D extends string, R, Ret> = {
28 readonly [Tag in Types.Tags<D, R> & string]: (_: Extract<R, Record<D, Tag>>) => Ret
29}
30
31type PartialTagHandlers<D extends string, R, Ret> = {
32 readonly [Tag in Types.Tags<D, R> & string]?: ((_: Extract<R, Record<D, Tag>>) => Ret) | undefined
33}
34
35type ValueTagHandlers<I> = {
36 readonly [Tag in Types.Tags<"_tag", I> & string]: (_: Extract<I, { readonly _tag: Tag }>) => any
37}
38
39/**
40 * Marker used by `Matcher` to distinguish matchers created with `Match.value`.
41 *
42 * @category models
43 * @since 4.0.0
44 */
45export type ValueFlavor = "value"
46
47/**
48 * Union type for matchers created by `Match.type` and `Match.value`.
49 *
50 * **Details**
51 *
52 * A `Matcher` carries the input type, accumulated filters, remaining cases,
53 * result type, and a flavor distinguishing the two matcher variants: `never`
54 * for matchers created with `Match.type` and `ValueFlavor` for matchers created
55 * with `Match.value`. Because the flavor never depends on the input type,
56 * terminal combinators resolve even when the input contains type parameters.
57 *
58 * **Example** (Matching string and number values)
59 *
60 * ```ts import.meta.vitest
61 * import { Match } from "effect"
62 *
63 * // Simulated dynamic input that can be a string or a number
64 * const input: string | number = "some input"
65 *
66 * // ┌─── string
67 * // ▼
68 * const result = Match.value(input).pipe(
69 * // Match if the value is a number
70 * Match.when(Match.number, (n) => `number: ${n}`),
71 * // Match if the value is a string
72 * Match.when(Match.string, (s) => `string: ${s}`),
73 * // Ensure all possible cases are covered
74 * Match.exhaustive
75 * )
76 *
77 * result // => "string: some input"
78 * ```
79 *
80 * @category models
81 * @since 4.0.0
82 */
83export type Matcher<
84 Input,
85 Filters,
86 RemainingApplied,
87 Result,
88 Flavor,
89 Return = any,
90 Args extends Array<any> = []
91> =
92 | TypeMatcher<Input, Filters, RemainingApplied, Result, Return, Args>
93 | ValueMatcher<Input, Filters, RemainingApplied, Result, Input, Return, Flavor>
94
95/**
96 * Represents a pattern matcher that operates on types rather than specific values.
97 *
98 * **Details**
99 *
100 * A `TypeMatcher` is created when using `Match.type<T>()` and allows you to define
101 * patterns that will be applied to values of the specified type. It maintains
102 * type-level information about the input type, applied filters, remaining cases,
103 * and expected results.
104 *
105 * **Example** (Creating a type matcher)
106 *
107 * ```ts import.meta.vitest
108 * import { Match } from "effect"
109 *
110 * // Create a TypeMatcher for string | number
111 * const matcher = Match.type<string | number>().pipe(
112 * Match.when(Match.string, (s) => `String: ${s}`),
113 * Match.when(Match.number, (n) => `Number: ${n}`),
114 * Match.exhaustive
115 * )
116 *
117 * matcher("hello") // => "String: hello"
118 * matcher(42) // => "Number: 42"
119 * ```
120 *
121 * @category models
122 * @since 4.0.0
123 */
124export interface TypeMatcher<
125 in Input,
126 out Filters,
127 out Remaining,
128 out Result,
129 out Return = any,
130 in Args extends Array<any> = []
131> extends Pipeable {
132 readonly _tag: "TypeMatcher"
133 readonly [TypeId]: {
134 readonly _input: T.Contravariant<Input>
135 readonly _filters: T.Covariant<Filters>
136 readonly _remaining: T.Covariant<Remaining>
137 readonly _result: T.Covariant<Result>
138 readonly _return: T.Covariant<Return>
139 readonly _args: T.Contravariant<Args>
140 }
141 readonly cases: ReadonlyArray<Case>
142 readonly select: (...args: Array<any>) => unknown
143 add<I, R, RA, A>(_case: Case): TypeMatcher<I, R, RA, A, Return, Args>
144}
145
146/**
147 * Represents a pattern matcher that operates on a specific provided value.
148 *
149 * **Details**
150 *
151 * A `ValueMatcher` is created when using `Match.value(someValue)` and contains
152 * the actual value to be matched against. It tracks both the provided value
153 * and the result of applying patterns to determine matches. Its optional
154 * seventh type parameter is the matcher flavor and defaults to `ValueFlavor`.
155 *
156 * **Example** (Creating a value matcher)
157 *
158 * ```ts import.meta.vitest
159 * import { Match } from "effect"
160 *
161 * const input = { type: "user", name: "Alice", age: 30 }
162 *
163 * // Create a ValueMatcher for the specific input
164 * const result = Match.value(input).pipe(
165 * Match.when({ type: "user" }, (user) => `User: ${user.name}`),
166 * Match.when({ type: "admin" }, (admin) => `Admin: ${admin.name}`),
167 * Match.orElse(() => "Unknown type")
168 * )
169 *
170 * result // => "User: Alice"
171 * ```
172 *
173 * @category models
174 * @since 4.0.0
175 */
176export interface ValueMatcher<
177 in Input,
178 Filters,
179 out Remaining,
180 out Result,
181 Provided,
182 out Return = any,
183 out Flavor = ValueFlavor
184> extends Pipeable {
185 readonly _tag: "ValueMatcher"
186 readonly [TypeId]: {
187 readonly _input: T.Contravariant<Input>
188 readonly _filters: T.Covariant<Filters>
189 readonly _result: T.Covariant<Result>
190 readonly _return: T.Covariant<Return>
191 readonly _flavor: T.Covariant<Flavor>
192 }
193 readonly provided: Provided
194 readonly value: Result.Result<Provided, Remaining>
195 add<I, R, RA, A, Provided>(_case: Case): ValueMatcher<I, R, RA, A, Provided>
196}
197
198/**
199 * Represents a single pattern matching case.
200 *
201 * **When to use**
202 *
203 * Use as the common public type for code that needs to inspect, store, or pass
204 * either positive or negative pattern matching cases.
205 *
206 * **Details**
207 *
208 * A `Case` can be either a positive match (`When`) or a negative match (`Not`).
209 * Cases are the building blocks of pattern matching logic and determine
210 * how values are tested and transformed.
211 *
212 * @see {@link When} for positive cases
213 * @see {@link Not} for negative cases
214 *
215 * @category models
216 * @since 4.0.0
217 */
218export type Case = When | Not
219
220/**
221 * Represents a positive pattern matching case.
222 *
223 * **Details**
224 *
225 * A `When` case contains the logic to test if a value matches a specific pattern
226 * and the function to evaluate when the pattern matches. It's the primary
227 * building block for pattern matching conditions.
228 *
229 * **Example** (Creating positive match cases)
230 *
231 * ```ts import.meta.vitest
232 * import { Match } from "effect"
233 *
234 * // When creates cases that match specific patterns
235 * const stringMatcher = Match.type<string | number>().pipe(
236 * Match.when(Match.string, (s: string) => `Got string: ${s}`),
237 * Match.when(Match.number, (n: number) => `Got number: ${n}`),
238 * Match.exhaustive
239 * )
240 *
241 * stringMatcher("hello") // => "Got string: hello"
242 * stringMatcher(42) // => "Got number: 42"
243 * ```
244 *
245 * @category models
246 * @since 4.0.0
247 */
248export interface When {
249 readonly _tag: "When"
250 guard(u: unknown): boolean
251 evaluate(input: unknown, ...args: Array<any>): any
252}
253
254/**
255 * Represents a negative pattern matching case.
256 *
257 * **Details**
258 *
259 * A `Not` case contains the logic to test if a value does NOT match a specific
260 * pattern and the function to evaluate when the pattern doesn't match. It's used
261 * for exclusion-based pattern matching.
262 *
263 * **Example** (Creating negative match cases)
264 *
265 * ```ts import.meta.vitest
266 * import { Match } from "effect"
267 *
268 * // Not creates cases that exclude specific patterns
269 * const matcher = Match.type<string>().pipe(
270 * // Match any string except "forbidden"
271 * Match.not("forbidden", (s) => `Allowed: ${s}`),
272 * Match.orElse(() => "This string is forbidden")
273 * )
274 *
275 * matcher("hello") // => "Allowed: hello"
276 * matcher("forbidden") // => "This string is forbidden"
277 * ```
278 *
279 * @category models
280 * @since 4.0.0
281 */
282export interface Not {
283 readonly _tag: "Not"
284 guard(u: unknown): boolean
285 evaluate(input: unknown, ...args: Array<any>): any
286}
287
288/**
289 * Creates a matcher for a specific type.
290 *
291 * **When to use**
292 *
293 * Use to build a reusable matcher function for values of a known input type.
294 *
295 * **Details**
296 *
297 * This function defines a `Matcher` that operates on a given type, allowing you
298 * to specify conditions for handling different cases. Once the matcher is
299 * created, you can use pattern-matching functions like {@link when} to define
300 * how different values should be processed.
301 *
302 * **Example** (Matching Numbers and Strings)
303 *
304 * ```ts import.meta.vitest
305 * import { Match } from "effect"
306 *
307 * // Create a matcher for values that are either strings or numbers
308 * //
309 * // ┌─── (u: string | number) => string
310 * // ▼
311 * const match = Match.type<string | number>().pipe(
312 * // Match when the value is a number
313 * Match.when(Match.number, (n) => `number: ${n}`),
314 * // Match when the value is a string
315 * Match.when(Match.string, (s) => `string: ${s}`),
316 * // Ensure all possible cases are handled
317 * Match.exhaustive
318 * )
319 *
320 * match(0) // => "number: 0"
321 *
322 * match("hello") // => "string: hello"
323 * ```
324 *
325 * @see {@link value} for creating a matcher from a specific value.
326 *
327 * @category constructors
328 * @since 4.0.0
329 */
330export const type: <I>() => Matcher<I, Types.Without<never>, I, never, never> = internal.type
331
332/**
333 * Creates a reusable matcher from a function that selects the value to match.
334 *
335 * **Details**
336 *
337 * The compiled matcher keeps the selector's original argument list. Case
338 * handlers receive the narrowed selected value followed by those arguments.
339 *
340 * **Example** (Creating a reusable matcher)
341 *
342 * ```ts import.meta.vitest
343 * import { Match } from "effect"
344 *
345 * const format = Match.fn((prefix: string, value: "a" | "b") => value).pipe(
346 * Match.when("a", (_value, prefix) => `${prefix}: A`),
347 * Match.when("b", (_value, prefix) => `${prefix}: B`),
348 * Match.exhaustive
349 * )
350 *
351 * format("status", "a") // => "status: A"
352 * ```
353 *
354 * @category constructors
355 * @since 4.0.0
356 */
357export const fn: <Args extends Array<any>, I>(
358 select: (...args: Args) => I
359) => Matcher<I, Types.Without<never>, I, never, never, any, Args> = internal.fn
360
361/**
362 * Creates a matcher from a specific value.
363 *
364 * **When to use**
365 *
366 * Use to match one concrete input immediately.
367 *
368 * **Details**
369 *
370 * This function allows you to define a `Matcher` directly from a given value,
371 * rather than from a type. This is useful when working with known values,
372 * enabling structured pattern matching on objects, primitives, or any data
373 * structure.
374 *
375 * Once the matcher is created, you can use pattern-matching functions like
376 * {@link when} to define how different cases should be handled.
377 *
378 * **Example** (Matching an Object by Property)
379 *
380 * ```ts import.meta.vitest
381 * import { Match } from "effect"
382 *
383 * const input = { name: "John", age: 30 }
384 *
385 * // Create a matcher for the specific object
386 * const result = Match.value(input).pipe(
387 * // Match when the 'name' property is "John"
388 * Match.when(
389 * { name: "John" },
390 * (user) => `${user.name} is ${user.age} years old`
391 * ),
392 * // Provide a fallback if no match is found
393 * Match.orElse(() => "Oh, not John")
394 * )
395 *
396 * result // => "John is 30 years old"
397 * ```
398 *
399 * @see {@link type} for creating a matcher from a specific type.
400 *
401 * @category constructors
402 * @since 4.0.0
403 */
404export const value: <const I>(
405 i: I
406) => Matcher<I, Types.Without<never>, I, never, ValueFlavor> = internal.value
407
408/**
409 * Creates a match function for a specific value with discriminated union handling.
410 *
411 * **Details**
412 *
413 * This function provides a convenient way to pattern match on discriminated unions
414 * by providing an object that maps each `_tag` value to its corresponding handler.
415 * It's similar to a switch statement but with better type safety and exhaustiveness checking.
416 *
417 * **Example** (Matching value tags)
418 *
419 * ```ts import.meta.vitest
420 * import { Match } from "effect"
421 *
422 * type Status = { readonly _tag: "Success"; readonly data: string }
423 *
424 * const success: Status = { _tag: "Success", data: "Hello" }
425 *
426 * // Simple valueTags usage
427 * const message = Match.valueTags(success, {
428 * Success: (result) => `Success: ${result.data}`
429 * })
430 *
431 * message // => "Success: Hello"
432 * ```
433 *
434 * @category constructors
435 * @since 4.0.0
436 */
437export const valueTags: {
438 <
439 const I,
440 P extends
441 & ValueTagHandlers<I>
442 & { readonly [Tag in Exclude<keyof P, Types.Tags<"_tag", I>>]: never }
443 >(
444 fields: Contextual<P, ValueTagHandlers<I>>
445 ): (input: I) => Unify<ReturnType<P[keyof P]>>
446 <
447 const I,
448 P extends
449 & ValueTagHandlers<I>
450 & { readonly [Tag in Exclude<keyof P, Types.Tags<"_tag", I>>]: never }
451 >(
452 input: I,
453 fields: Contextual<P, ValueTagHandlers<I>>
454 ): Unify<ReturnType<P[keyof P]>>
455} = internal.valueTags
456
457/**
458 * Creates a type-safe match function for discriminated unions based on `_tag` field.
459 *
460 * **Details**
461 *
462 * This function allows you to define exhaustive pattern matching for discriminated unions
463 * by providing handlers for each possible `_tag` value. It ensures type safety and
464 * can optionally enforce a specific return type across all branches.
465 *
466 * **Example** (Matching type tags)
467 *
468 * ```ts import.meta.vitest
469 * import { Match } from "effect"
470 *
471 * type Result =
472 * | { readonly _tag: "Success"; readonly data: string }
473 * | { readonly _tag: "Error"; readonly message: string }
474 * | { readonly _tag: "Loading" }
475 *
476 * // Create a matcher with specific return type
477 * const formatResult = Match.typeTags<Result, string>()({
478 * Success: (result) => `Data: ${result.data}`,
479 * Error: (result) => `Error: ${result.message}`,
480 * Loading: () => "Loading..."
481 * })
482 *
483 * formatResult({ _tag: "Success", data: "Hello World" }) // => "Data: Hello World"
484 *
485 * formatResult({ _tag: "Error", message: "Network failed" }) // => "Error: Network failed"
486 *
487 * // Create a matcher with inferred return type
488 * const processResult = Match.typeTags<Result>()({
489 * Success: (result) => ({ type: "ok", value: result.data }),
490 * Error: (result) => ({ type: "error", error: result.message }),
491 * Loading: () => ({ type: "pending" })
492 * })
493 *
494 * processResult({ _tag: "Loading" }) // => { type: "pending" }
495 * ```
496 *
497 * @category constructors
498 * @since 4.0.0
499 */
500export const typeTags: {
501 <I, Ret>(): <
502 P extends
503 & {
504 readonly [Tag in Types.Tags<"_tag", I> & string]: (
505 _: Extract<I, { readonly _tag: Tag }>
506 ) => Ret
507 }
508 & { readonly [Tag in Exclude<keyof P, Types.Tags<"_tag", I>>]: never }
509 >(fields: P) => (input: I) => Ret
510 <I>(): <
511 P extends
512 & {
513 readonly [Tag in Types.Tags<"_tag", I> & string]: (
514 _: Extract<I, { readonly _tag: Tag }>
515 ) => any
516 }
517 & { readonly [Tag in Exclude<keyof P, Types.Tags<"_tag", I>>]: never }
518 >(fields: P) => (input: I) => Unify<ReturnType<P[keyof P]>>
519} = internal.typeTags
520
521/**
522 * Ensures that all branches of a matcher return a specific type.
523 *
524 * **Details**
525 *
526 * This function enforces a consistent return type across all pattern-matching
527 * branches. By specifying a return type, TypeScript will check that every
528 * matching condition produces a value of the expected type.
529 *
530 * **Important:** This function must be the first step in the matcher pipeline.
531 * If used later, TypeScript will not enforce type consistency correctly.
532 *
533 * **Example** (Validating return type consistency)
534 *
535 * ```ts import.meta.vitest
536 * import { Match } from "effect"
537 *
538 * const match = Match.type<{ a: number } | { b: string }>().pipe(
539 * // Ensure all branches return a string
540 * Match.withReturnType<string>(),
541 * // ❌ Type error: 'number' is not assignable to type 'string'
542 * // @ts-expect-error
543 * Match.when({ a: Match.number }, (_) => _.a),
544 * // ✅ Correct: returns a string
545 * Match.when({ b: Match.string }, (_) => _.b),
546 * Match.exhaustive
547 * )
548 * ```
549 *
550 * @category utility types
551 * @since 4.0.0
552 */
553export const withReturnType: <Ret>() => <I, F, R, A, Pr, _, Args extends Array<any>>(
554 self: Matcher<I, F, R, A, Pr, _, Args>
555) => [Ret] extends [[A] extends [never] ? any : A] ? Matcher<I, F, R, A, Pr, Ret, Args>
556 : "withReturnType constraint does not extend Result type" = internal.withReturnType
557
558/**
559 * Defines a condition for matching values.
560 *
561 * **When to use**
562 *
563 * Use to add one positive pattern case to a `Match.type` or `Match.value`
564 * pipeline when a direct value, predicate, or structured object pattern should
565 * run a handler for matching input.
566 *
567 * **Details**
568 *
569 * Supports both direct value comparisons and predicate functions. If the
570 * pattern matches, the associated function is executed and the matched input is
571 * removed from the remaining cases tracked by the matcher.
572 *
573 * **Example** (Matching with values and predicates)
574 *
575 * ```ts import.meta.vitest
576 * import { Match } from "effect"
577 *
578 * // Create a matcher for objects with an "age" property
579 * const match = Match.type<{ age: number }>().pipe(
580 * // Match when age is greater than 18
581 * Match.when(
582 * { age: (age: number) => age > 18 },
583 * (user: { age: number }) => `Age: ${user.age}`
584 * ),
585 * // Match when age is exactly 18
586 * Match.when({ age: 18 }, () => "You can vote"),
587 * // Fallback case for all other ages
588 * Match.orElse((user: { age: number }) => `${user.age} is too young`)
589 * )
590 *
591 * match({ age: 20 }) // => "Age: 20"
592 *
593 * match({ age: 18 }) // => "You can vote"
594 *
595 * match({ age: 4 }) // => "4 is too young"
596 * ```
597 *
598 * @see {@link whenOr} for handling any one of several patterns with the same handler
599 * @see {@link whenAnd} for requiring all provided patterns to match before running a handler
600 * @see {@link not} for handling inputs that do not match a pattern
601 * @see {@link orElse} for providing a fallback when no pattern case matches
602 *
603 * @category defining patterns
604 * @since 4.0.0
605 */
606export const when: <
607 R,
608 const P extends Types.PatternPrimitive<R> | Types.PatternBase<R>,
609 Ret,
610 Args extends Array<any>,
611 Fn extends (_: Types.WhenMatch<R, P>, ...args: Args) => Ret
612>(
613 pattern: P,
614 f: Fn
615) => <I, F, A, Pr>(
616 self: Matcher<I, F, R, A, Pr, Ret, Args>
617) => Matcher<
618 I,
619 Types.AddWithout<F, Types.PForExclude<P>>,
620 Types.ApplyFilters<I, Types.AddWithout<F, Types.PForExclude<P>>>,
621 A | ReturnType<Fn>,
622 Pr,
623 Ret,
624 Args
625> = internal.when
626
627/**
628 * Matches one of multiple patterns in a single condition.
629 *
630 * **Details**
631 *
632 * This function allows defining a condition where a value matches any of the
633 * provided patterns. If a match is found, the associated function is executed.
634 * It simplifies cases where multiple patterns share the same handling logic.
635 *
636 * Unlike {@link when}, which requires separate conditions for each pattern,
637 * this function enables combining them into a single statement, making the
638 * matcher more concise.
639 *
640 * **Example** (Matching one of several patterns)
641 *
642 * ```ts import.meta.vitest
643 * import { Match } from "effect"
644 *
645 * type ErrorType =
646 * | { readonly _tag: "NetworkError"; readonly message: string }
647 * | { readonly _tag: "TimeoutError"; readonly duration: number }
648 * | { readonly _tag: "ValidationError"; readonly field: string }
649 *
650 * const handleError = Match.type<ErrorType>().pipe(
651 * Match.whenOr(
652 * { _tag: "NetworkError" },
653 * { _tag: "TimeoutError" },
654 * () => "Retry the request"
655 * ),
656 * Match.when({ _tag: "ValidationError" }, (_) => `Invalid field: ${_.field}`),
657 * Match.exhaustive
658 * )
659 *
660 * handleError({ _tag: "NetworkError", message: "No connection" }) // => "Retry the request"
661 *
662 * handleError({ _tag: "ValidationError", field: "email" }) // => "Invalid field: email"
663 * ```
664 *
665 * @category defining patterns
666 * @since 4.0.0
667 */
668export const whenOr: <
669 R,
670 const P extends ReadonlyArray<Types.PatternPrimitive<R> | Types.PatternBase<R>>,
671 Ret,
672 Args extends Array<any>,
673 Fn extends (_: Types.WhenMatch<R, P[number]>, ...args: Args) => Ret
674>(
675 ...args: [...patterns: P, f: Fn]
676) => <I, F, A, Pr>(
677 self: Matcher<I, F, R, A, Pr, Ret, Args>
678) => Matcher<
679 I,
680 Types.AddWithout<F, Types.PForExclude<P[number]>>,
681 Types.ApplyFilters<I, Types.AddWithout<F, Types.PForExclude<P[number]>>>,
682 A | ReturnType<Fn>,
683 Pr,
684 Ret,
685 Args
686> = internal.whenOr
687
688/**
689 * Matches a value that satisfies all provided patterns.
690 *
691 * **Details**
692 *
693 * This function allows defining a condition where a value must match all the
694 * given patterns simultaneously. If the value satisfies every pattern, the
695 * associated function is executed.
696 *
697 * Unlike {@link when}, which matches a single pattern at a time, this function
698 * ensures that multiple conditions are met before executing the callback. It is
699 * useful when checking for values that need to fulfill multiple criteria at
700 * once.
701 *
702 * **Example** (Matching all provided patterns)
703 *
704 * ```ts import.meta.vitest
705 * import { Match } from "effect"
706 *
707 * type User = { readonly age: number; readonly role: "admin" | "user" }
708 *
709 * const checkUser = Match.type<User>().pipe(
710 * Match.whenAnd(
711 * { age: (n) => n >= 18 },
712 * { role: "admin" },
713 * () => "Admin access granted"
714 * ),
715 * Match.orElse(() => "Access denied")
716 * )
717 *
718 * checkUser({ age: 20, role: "admin" }) // => "Admin access granted"
719 *
720 * checkUser({ age: 20, role: "user" }) // => "Access denied"
721 * ```
722 *
723 * @category defining patterns
724 * @since 4.0.0
725 */
726export const whenAnd: <
727 R,
728 const P extends ReadonlyArray<Types.PatternPrimitive<R> | Types.PatternBase<R>>,
729 Ret,
730 Args extends Array<any>,
731 Fn extends (_: Types.WhenMatch<R, T.UnionToIntersection<P[number]>>, ...args: Args) => Ret
732>(
733 ...args: [...patterns: P, f: Fn]
734) => <I, F, A, Pr>(
735 self: Matcher<I, F, R, A, Pr, Ret, Args>
736) => Matcher<
737 I,
738 Types.AddWithout<F, Types.PForExclude<T.UnionToIntersection<P[number]>>>,
739 Types.ApplyFilters<I, Types.AddWithout<F, Types.PForExclude<T.UnionToIntersection<P[number]>>>>,
740 A | ReturnType<Fn>,
741 Pr,
742 Ret,
743 Args
744> = internal.whenAnd
745
746/**
747 * Matches values based on a specified discriminant field.
748 *
749 * **When to use**
750 *
751 * Use to match one or more exact values of a discriminator field.
752 *
753 * **Details**
754 *
755 * This function is used to define pattern matching on objects that follow a
756 * **discriminated union** structure, where a specific field (e.g., `type`,
757 * `kind`, `_tag`) determines the variant of the object. It allows matching
758 * multiple values of the discriminant and provides a function to handle the
759 * matched cases.
760 *
761 * **Example** (Matching on a discriminator field)
762 *
763 * ```ts import.meta.vitest
764 * import { Match, pipe } from "effect"
765 *
766 * const match = pipe(
767 * Match.type<
768 * { type: "A"; a: string } | { type: "B"; b: number } | {
769 * type: "C"
770 * c: boolean
771 * }
772 * >(),
773 * Match.discriminator("type")("A", "B", (_) => `A or B: ${_.type}`),
774 * Match.discriminator("type")("C", (_) => `C(${_.c})`),
775 * Match.exhaustive
776 * )
777 * match({ type: "A", a: "ok" }) // => "A or B: A"
778 * match({ type: "C", c: true }) // => "C(true)"
779 * ```
780 *
781 * @see {@link discriminators} for defining several discriminator handlers at once
782 * @see {@link discriminatorStartsWith} for matching string discriminator values by prefix
783 *
784 * @category defining patterns
785 * @since 4.0.0
786 */
787export const discriminator: <D extends string>(
788 field: D
789) => <R, P extends Types.Tags<D, R> & string, Ret, Fn extends (_: Extract<R, Record<D, P>>) => Ret>(
790 ...pattern: [first: P, ...values: Array<P>, f: Fn]
791) => <I, F, A, Pr>(
792 self: Matcher<I, F, R, A, Pr, Ret>
793) => Matcher<
794 I,
795 Types.AddWithout<F, Extract<R, Record<D, P>>>,
796 Types.ApplyFilters<I, Types.AddWithout<F, Extract<R, Record<D, P>>>>,
797 A | ReturnType<Fn>,
798 Pr,
799 Ret
800> = internal.discriminator
801
802/**
803 * Matches values where a specified field starts with a given prefix.
804 *
805 * **When to use**
806 *
807 * Use to match string discriminator values by prefix instead of exact value.
808 *
809 * **Details**
810 *
811 * Instead of checking for exact matches, this helper matches values that share
812 * a common prefix. For example, if the discriminant field contains hierarchical
813 * names like `"A"`, `"A.A"`, and `"B"`, a single `"A"` rule can match both
814 * `"A"` and `"A.A"`.
815 *
816 * **Example** (Matching discriminator prefixes)
817 *
818 * ```ts import.meta.vitest
819 * import { Match, pipe } from "effect"
820 *
821 * const match = pipe(
822 * Match.type<{ type: "A" } | { type: "B" } | { type: "A.A" } | {}>(),
823 * Match.discriminatorStartsWith("type")("A", (_) => 1 as const),
824 * Match.discriminatorStartsWith("type")("B", (_) => 2 as const),
825 * Match.orElse((_) => 3 as const)
826 * )
827 *
828 * match({ type: "A" }) // => 1
829 * match({ type: "B" }) // => 2
830 * match({ type: "A.A" }) // => 1
831 * ```
832 *
833 * @see {@link discriminator} for matching exact discriminator values
834 *
835 * @category defining patterns
836 * @since 4.0.0
837 */
838export const discriminatorStartsWith: <D extends string>(
839 field: D
840) => <R, P extends string, Ret, Fn extends (_: Extract<R, Record<D, `${P}${string}`>>) => Ret>(
841 pattern: P,
842 f: Fn
843) => <I, F, A, Pr>(
844 self: Matcher<I, F, R, A, Pr, Ret>
845) => Matcher<
846 I,
847 Types.AddWithout<F, Extract<R, Record<D, `${P}${string}`>>>,
848 Types.ApplyFilters<I, Types.AddWithout<F, Extract<R, Record<D, `${P}${string}`>>>>,
849 A | ReturnType<Fn>,
850 Pr,
851 Ret
852> = internal.discriminatorStartsWith
853
854/**
855 * Matches values based on a field that serves as a discriminator, mapping each
856 * possible value to a corresponding handler.
857 *
858 * **When to use**
859 *
860 * Use to define several discriminator handlers at once without finalizing the
861 * matcher.
862 *
863 * **Details**
864 *
865 * This function simplifies working with discriminated unions by letting you
866 * define a set of handlers for each possible value of a given field. Instead of
867 * chaining multiple calls to {@link discriminator}, this function allows
868 * defining all possible cases at once using an object where the keys are the
869 * possible values of the field, and the values are the corresponding handler
870 * functions.
871 *
872 * **Example** (Mapping discriminator handlers)
873 *
874 * ```ts import.meta.vitest
875 * import { Match, pipe } from "effect"
876 *
877 * const match = pipe(
878 * Match.type<
879 * { type: "A"; a: string } | { type: "B"; b: number } | {
880 * type: "C"
881 * c: boolean
882 * }
883 * >(),
884 * Match.discriminators("type")({
885 * A: (a) => a.a,
886 * B: (b) => b.b,
887 * C: (c) => c.c
888 * }),
889 * Match.exhaustive
890 * )
891 * match({ type: "A", a: "ok" }) // => "ok"
892 * match({ type: "B", b: 42 }) // => 42
893 * ```
894 *
895 * @see {@link discriminator} for adding one discriminator case to a matcher pipeline
896 * @see {@link discriminatorsExhaustive} for handling every discriminator value and finalizing the matcher
897 *
898 * @category defining patterns
899 * @since 4.0.0
900 */
901export const discriminators: <D extends string>(
902 field: D
903) => <
904 R,
905 Ret,
906 P extends
907 & PartialTagHandlers<D, R, Ret>
908 & { readonly [Tag in Exclude<keyof P, Types.Tags<D, R>>]: never }
909>(
910 fields: Contextual<P, PartialTagHandlers<D, R, Ret>>
911) => <I, F, A, Pr>(
912 self: Matcher<I, F, R, A, Pr, Ret>
913) => Matcher<
914 I,
915 Types.AddWithout<F, Extract<R, Record<D, keyof P>>>,
916 Types.ApplyFilters<I, Types.AddWithout<F, Extract<R, Record<D, keyof P>>>>,
917 A | ReturnType<P[keyof P] & {}>,
918 Pr,
919 Ret
920> = internal.discriminators
921
922/**
923 * Matches values by a discriminator field and requires every possible case to
924 * be handled.
925 *
926 * **When to use**
927 *
928 * Use to define an exhaustive discriminator handler map that finalizes the
929 * matcher.
930 *
931 * **Details**
932 *
933 * This is the exhaustive variant of {@link discriminators}. Each possible
934 * discriminator value must have a corresponding handler, so the matcher is
935 * finalized directly and does not require `Match.exhaustive` at the end of the
936 * pipeline.
937 *
938 * **Example** (Handling all discriminator cases)
939 *
940 * ```ts import.meta.vitest
941 * import { Match, pipe } from "effect"
942 *
943 * const match = pipe(
944 * Match.type<
945 * { type: "A"; a: string } | { type: "B"; b: number } | {
946 * type: "C"
947 * c: boolean
948 * }
949 * >(),
950 * Match.discriminatorsExhaustive("type")({
951 * A: (a) => a.a,
952 * B: (b) => b.b,
953 * C: (c) => c.c
954 * })
955 * )
956 * match({ type: "C", c: true }) // => true
957 * ```
958 *
959 * @see {@link discriminators} for defining discriminator handlers without finalizing the matcher
960 *
961 * @category defining patterns
962 * @since 4.0.0
963 */
964export const discriminatorsExhaustive: <D extends string>(
965 field: D
966) => <
967 R,
968 Ret,
969 P extends
970 & TagHandlers<D, R, Ret>
971 & { readonly [Tag in Exclude<keyof P, Types.Tags<D, R>>]: never }
972>(
973 fields: Contextual<P, TagHandlers<D, R, Ret>>
974) => <I, F, A, Pr>(
975 self: Matcher<I, F, R, A, Pr, Ret>
976) => [Pr] extends [never] ? (u: I) => Unify<A | ReturnType<P[keyof P]>> : Unify<A | ReturnType<P[keyof P]>> =
977 internal.discriminatorsExhaustive
978
979/**
980 * Matches discriminated union members by their `_tag` field.
981 *
982 * **When to use**
983 *
984 * Use to handle one or more `_tag` cases with the same matcher branch.
985 *
986 * **Details**
987 *
988 * This helper follows the Effect convention that discriminated unions use
989 * `"_tag"` as their discriminator field. Use {@link discriminator} for a
990 * different discriminator field.
991 *
992 * **Example** (Matching a discriminated union by tag)
993 *
994 * ```ts import.meta.vitest
995 * import { Match } from "effect"
996 *
997 * type Event =
998 * | { readonly _tag: "fetch" }
999 * | { readonly _tag: "success"; readonly data: string }
1000 * | { readonly _tag: "error"; readonly error: Error }
1001 * | { readonly _tag: "cancel" }
1002 *
1003 * const match = Match.type<Event>().pipe(
1004 * // Match either "fetch" or "success"
1005 * Match.tag("fetch", "success", () => `Ok!`),
1006 * // Match "error" and extract the error message
1007 * Match.tag("error", (event) => `Error: ${event.error.message}`),
1008 * // Match "cancel"
1009 * Match.tag("cancel", () => "Cancelled"),
1010 * Match.exhaustive
1011 * )
1012 *
1013 * match({ _tag: "success", data: "Hello" }) // => "Ok!"
1014 *
1015 * match({ _tag: "error", error: new Error("Oops!") }) // => "Error: Oops!"
1016 * ```
1017 *
1018 * @category defining patterns
1019 * @since 4.0.0
1020 */
1021export const tag: <
1022 R,
1023 P extends Types.Tags<"_tag", R> & string,
1024 Ret,
1025 Args extends Array<any>,
1026 Fn extends (_: Extract<R, Record<"_tag", P>>, ...args: Args) => Ret
1027>(
1028 ...pattern: [first: P, ...values: Array<P>, f: Fn]
1029) => <I, F, A, Pr>(
1030 self: Matcher<I, F, R, A, Pr, Ret, Args>
1031) => Matcher<
1032 I,
1033 Types.AddWithout<F, Extract<R, Record<"_tag", P>>>,
1034 Types.ApplyFilters<I, Types.AddWithout<F, Extract<R, Record<"_tag", P>>>>,
1035 ReturnType<Fn> | A,
1036 Pr,
1037 Ret,
1038 Args
1039> = internal.tag
1040
1041/**
1042 * Matches values where the `_tag` field starts with a given prefix.
1043 *
1044 * **Details**
1045 *
1046 * This function allows you to match on values in a **discriminated union**
1047 * based on whether the `_tag` field starts with a specified prefix. It is
1048 * useful for handling hierarchical or namespaced tags, where multiple related
1049 * cases share a common prefix.
1050 *
1051 * **Example** (Matching tag prefixes)
1052 *
1053 * ```ts import.meta.vitest
1054 * import { Match, pipe } from "effect"
1055 *
1056 * const match = pipe(
1057 * Match.type<{ _tag: "A" } | { _tag: "B" } | { _tag: "A.A" } | {}>(),
1058 * Match.tagStartsWith("A", (_) => 1 as const),
1059 * Match.tagStartsWith("B", (_) => 2 as const),
1060 * Match.orElse((_) => 3 as const)
1061 * )
1062 *
1063 * match({ _tag: "A" }) // => 1
1064 * match({ _tag: "B" }) // => 2
1065 * match({ _tag: "A.A" }) // => 1
1066 * ```
1067 *
1068 * @category defining patterns
1069 * @since 4.0.0
1070 */
1071export const tagStartsWith: <
1072 R,
1073 P extends string,
1074 Ret,
1075 Fn extends (_: Extract<R, Record<"_tag", `${P}${string}`>>) => Ret
1076>(
1077 pattern: P,
1078 f: Fn
1079) => <I, F, A, Pr>(
1080 self: Matcher<I, F, R, A, Pr, Ret>
1081) => Matcher<
1082 I,
1083 Types.AddWithout<F, Extract<R, Record<"_tag", `${P}${string}`>>>,
1084 Types.ApplyFilters<I, Types.AddWithout<F, Extract<R, Record<"_tag", `${P}${string}`>>>>,
1085 ReturnType<Fn> | A,
1086 Pr,
1087 Ret
1088> = internal.tagStartsWith
1089
1090/**
1091 * Matches values based on their `_tag` field, mapping each tag to a
1092 * corresponding handler.
1093 *
1094 * **Details**
1095 *
1096 * This function provides a way to handle discriminated unions by mapping `_tag`
1097 * values to specific functions. Each handler receives the matched value and
1098 * returns a transformed result. If all possible tags are handled, you can
1099 * enforce exhaustiveness using `Match.exhaustive` to ensure no case is missed.
1100 *
1101 * **Example** (Mapping tag handlers)
1102 *
1103 * ```ts import.meta.vitest
1104 * import { Match, pipe } from "effect"
1105 *
1106 * const match = pipe(
1107 * Match.type<
1108 * { _tag: "A"; a: string } | { _tag: "B"; b: number } | {
1109 * _tag: "C"
1110 * c: boolean
1111 * }
1112 * >(),
1113 * Match.tags({
1114 * A: (a) => a.a,
1115 * B: (b) => b.b,
1116 * C: (c) => c.c
1117 * }),
1118 * Match.exhaustive
1119 * )
1120 * match({ _tag: "A", a: "ok" }) // => "ok"
1121 * ```
1122 *
1123 * @category defining patterns
1124 * @since 4.0.0
1125 */
1126export const tags: <
1127 R,
1128 Ret,
1129 P extends
1130 & PartialTagHandlers<"_tag", R, Ret>
1131 & { readonly [Tag in Exclude<keyof P, Types.Tags<"_tag", R>>]: never }
1132>(
1133 fields: Contextual<P, PartialTagHandlers<"_tag", R, Ret>>
1134) => <I, F, A, Pr>(
1135 self: Matcher<I, F, R, A, Pr, Ret>
1136) => Matcher<
1137 I,
1138 Types.AddWithout<F, Extract<R, Record<"_tag", keyof P>>>,
1139 Types.ApplyFilters<I, Types.AddWithout<F, Extract<R, Record<"_tag", keyof P>>>>,
1140 A | ReturnType<P[keyof P] & {}>,
1141 Pr,
1142 Ret
1143> = internal.tags
1144
1145/**
1146 * Matches values based on their `_tag` field and requires handling of all
1147 * possible cases.
1148 *
1149 * **Details**
1150 *
1151 * This function is designed for **discriminated unions** where every possible
1152 * `_tag` value must have a corresponding handler. Unlike {@link tags}, this
1153 * function ensures **exhaustiveness**, meaning all cases must be explicitly
1154 * handled. If a `_tag` value is missing from the mapping, TypeScript will
1155 * report an error.
1156 *
1157 * **Example** (Handling all tag cases)
1158 *
1159 * ```ts import.meta.vitest
1160 * import { Match, pipe } from "effect"
1161 *
1162 * const match = pipe(
1163 * Match.type<
1164 * { _tag: "A"; a: string } | { _tag: "B"; b: number } | {
1165 * _tag: "C"
1166 * c: boolean
1167 * }
1168 * >(),
1169 * Match.tagsExhaustive({
1170 * A: (a) => a.a,
1171 * B: (b) => b.b,
1172 * C: (c) => c.c
1173 * })
1174 * )
1175 * match({ _tag: "B", b: 42 }) // => 42
1176 * ```
1177 *
1178 * @category defining patterns
1179 * @since 4.0.0
1180 */
1181export const tagsExhaustive: <
1182 R,
1183 Ret,
1184 P extends
1185 & TagHandlers<"_tag", R, Ret>
1186 & { readonly [Tag in Exclude<keyof P, Types.Tags<"_tag", R>>]: never }
1187>(
1188 fields: Contextual<P, TagHandlers<"_tag", R, Ret>>
1189) => <I, F, A, Pr>(
1190 self: Matcher<I, F, R, A, Pr, Ret>
1191) => [Pr] extends [never] ? (u: I) => Unify<A | ReturnType<P[keyof P]>> : Unify<A | ReturnType<P[keyof P]>> =
1192 internal.tagsExhaustive
1193
1194/**
1195 * Creates a pattern that excludes a specific value while allowing all others.
1196 *
1197 * **When to use**
1198 *
1199 * Use to add a negative pattern case for inputs that should match when another
1200 * pattern does not.
1201 *
1202 * **Details**
1203 *
1204 * Any excluded value bypasses the provided function and continues matching
1205 * through later cases.
1206 *
1207 * **Example** (Ignoring a specific value)
1208 *
1209 * ```ts import.meta.vitest
1210 * import { Match } from "effect"
1211 *
1212 * // Create a matcher for string or number values
1213 * const match = Match.type<string | number>().pipe(
1214 * // Match any value except "hi", returning "ok"
1215 * Match.not("hi", () => "ok"),
1216 * // Fallback case for when the value is "hi"
1217 * Match.orElse(() => "fallback")
1218 * )
1219 *
1220 * match("hello") // => "ok"
1221 *
1222 * match("hi") // => "fallback"
1223 * ```
1224 *
1225 * @see {@link when} for adding a positive pattern case
1226 *
1227 * @category defining patterns
1228 * @since 4.0.0
1229 */
1230export const not: <
1231 R,
1232 const P extends Types.PatternPrimitive<R> | Types.PatternBase<R>,
1233 Ret,
1234 Args extends Array<any>,
1235 Fn extends (_: Types.NotMatch<R, P>, ...args: Args) => Ret
1236>(
1237 pattern: P,
1238 f: Fn
1239) => <I, F, A, Pr>(
1240 self: Matcher<I, F, R, A, Pr, Ret, Args>
1241) => Matcher<
1242 I,
1243 Types.AddOnly<F, Types.WhenMatch<R, P>>,
1244 Types.ApplyFilters<I, Types.AddOnly<F, Types.WhenMatch<R, P>>>,
1245 A | ReturnType<Fn>,
1246 Pr,
1247 Ret,
1248 Args
1249> = internal.not
1250
1251/**
1252 * Matches non-empty strings.
1253 *
1254 * **When to use**
1255 *
1256 * Use to match strings whose length is greater than zero.
1257 *
1258 * **Details**
1259 *
1260 * This predicate matches any string that contains at least one character,
1261 * effectively filtering out empty strings ("").
1262 *
1263 * **Example** (Matching non-empty strings)
1264 *
1265 * ```ts import.meta.vitest
1266 * import { Match } from "effect"
1267 *
1268 * const processInput = Match.type<string>()
1269 * .pipe(
1270 * Match.when(Match.nonEmptyString, (str) => `Valid input: ${str}`),
1271 * Match.orElse(() => "Input cannot be empty")
1272 * )
1273 *
1274 * processInput("hello") // => "Valid input: hello"
1275 *
1276 * processInput("") // => "Input cannot be empty"
1277 *
1278 * processInput(" ") // => "Valid input: "
1279 * ```
1280 *
1281 * @see {@link string} for matching any string
1282 *
1283 * @category guards
1284 * @since 4.0.0
1285 */
1286export const nonEmptyString: SafeRefinement<string, never> = internal.nonEmptyString
1287
1288/**
1289 * Matches a specific set of literal values (e.g., `Match.is("a", 42, true)`).
1290 *
1291 * **When to use**
1292 *
1293 * Use to match one of several literal primitive or null values.
1294 *
1295 * **Details**
1296 *
1297 * This function creates a predicate that matches any of the provided literal values.
1298 * It's useful for matching against multiple specific values in a single pattern.
1299 *
1300 * **Example** (Matching literal values)
1301 *
1302 * ```ts import.meta.vitest
1303 * import { Match } from "effect"
1304 *
1305 * const handleStatus = Match.type<string | number>()
1306 * .pipe(
1307 * Match.when(Match.is("success", "ok", 200), () => "Operation successful"),
1308 * Match.when(Match.is("error", "failed", 500), () => "Operation failed"),
1309 * Match.when(Match.is(0, false, null), () => "Falsy value"),
1310 * Match.orElse((value) => `Unknown status: ${value}`)
1311 * )
1312 *
1313 * handleStatus("success") // => "Operation successful"
1314 *
1315 * handleStatus(200) // => "Operation successful"
1316 *
1317 * handleStatus("failed") // => "Operation failed"
1318 *
1319 * handleStatus(0) // => "Falsy value"
1320 *
1321 * handleStatus("pending") // => "Unknown status: pending"
1322 * ```
1323 *
1324 * @category guards
1325 * @since 4.0.0
1326 */
1327export const is: <
1328 Literals extends ReadonlyArray<string | number | bigint | boolean | null>
1329>(...literals: Literals) => SafeRefinement<Literals[number]> = internal.is
1330
1331/**
1332 * Matches values of type `string`.
1333 *
1334 * **Details**
1335 *
1336 * This predicate refines unknown values to strings, allowing pattern matching
1337 * on string types. It's commonly used in type-based matchers to handle string cases.
1338 *
1339 * **Example** (Matching string values)
1340 *
1341 * ```ts import.meta.vitest
1342 * import { Match } from "effect"
1343 *
1344 * const processValue = Match.type<string | number | boolean>().pipe(
1345 * Match.when(Match.string, (str) => `String: ${str.toUpperCase()}`),
1346 * Match.when(Match.number, (num) => `Number: ${num * 2}`),
1347 * Match.when(Match.boolean, (bool) => `Boolean: ${bool ? "yes" : "no"}`),
1348 * Match.exhaustive
1349 * )
1350 *
1351 * processValue("hello") // => "String: HELLO"
1352 * processValue(42) // => "Number: 84"
1353 * processValue(true) // => "Boolean: yes"
1354 * ```
1355 *
1356 * @category guards
1357 * @since 4.0.0
1358 */
1359export const string: Predicate.Refinement<unknown, string> = Predicate.isString
1360
1361/**
1362 * Matches values of type `number`.
1363 *
1364 * **When to use**
1365 *
1366 * Use to match primitive number values, including `NaN` and infinities.
1367 *
1368 * **Details**
1369 *
1370 * This predicate refines unknown values to numbers, allowing pattern matching
1371 * on numeric types. It matches all number values including integers, floats,
1372 * `Infinity`, `-Infinity`, and `NaN`.
1373 *
1374 * **Example** (Matching number values)
1375 *
1376 * ```ts import.meta.vitest
1377 * import { Match } from "effect"
1378 *
1379 * const categorizeNumber = Match.type<unknown>().pipe(
1380 * Match.when(Match.number, (num) => {
1381 * if (Number.isNaN(num)) return "Not a number"
1382 * if (!Number.isFinite(num)) return "Infinite"
1383 * if (Number.isInteger(num)) return `Integer: ${num}`
1384 * return `Float: ${num.toFixed(2)}`
1385 * }),
1386 * Match.orElse(() => "Not a number type")
1387 * )
1388 *
1389 * categorizeNumber(42) // => "Integer: 42"
1390 * categorizeNumber(3.14) // => "Float: 3.14"
1391 * categorizeNumber(NaN) // => "Not a number"
1392 * categorizeNumber("hello") // => "Not a number type"
1393 * ```
1394 *
1395 * @see {@link bigint} for matching primitive bigint values
1396 *
1397 * @category guards
1398 * @since 4.0.0
1399 */
1400export const number: Predicate.Refinement<unknown, number> = Predicate.isNumber
1401
1402/**
1403 * Matches any value without restrictions.
1404 *
1405 * **When to use**
1406 *
1407 * Use to define an explicit catch-all pattern when the handler should receive
1408 * the unmatched value.
1409 *
1410 * **Details**
1411 *
1412 * This predicate matches every input, including `undefined`, `null`, objects,
1413 * primitives, and functions.
1414 *
1415 * **Gotchas**
1416 *
1417 * `Match.any` should usually be last because cases are checked in order and
1418 * the first matching case wins.
1419 *
1420 * **Example** (Matching any remaining value)
1421 *
1422 * ```ts import.meta.vitest
1423 * import { Match } from "effect"
1424 *
1425 * const describeValue = Match.type<unknown>()
1426 * .pipe(
1427 * Match.when(Match.string, (str) => `String: ${str}`),
1428 * Match.when(Match.number, (num) => `Number: ${num}`),
1429 * Match.when(Match.boolean, (bool) => `Boolean: ${bool}`),
1430 * Match.when(Match.any, (value) => `Other: ${typeof value}`),
1431 * Match.exhaustive
1432 * )
1433 *
1434 * describeValue("hello") // => "String: hello"
1435 *
1436 * describeValue(42) // => "Number: 42"
1437 *
1438 * describeValue([1, 2, 3]) // => "Other: object"
1439 *
1440 * describeValue(null) // => "Other: object"
1441 * ```
1442 *
1443 * @see {@link defined} for matching only non-nullish values
1444 * @see {@link orElse} for providing a fallback after earlier cases
1445 *
1446 * @category guards
1447 * @since 4.0.0
1448 */
1449export const any: SafeRefinement<unknown, any> = internal.any
1450
1451/**
1452 * Matches any defined (non-null and non-undefined) value.
1453 *
1454 * **When to use**
1455 *
1456 * Use to exclude only `null` and `undefined` from a match branch.
1457 *
1458 * **Details**
1459 *
1460 * This predicate matches values that are neither `null` nor `undefined`,
1461 * effectively filtering out nullish values while preserving all other types.
1462 *
1463 * **Example** (Matching defined values)
1464 *
1465 * ```ts import.meta.vitest
1466 * import { Match } from "effect"
1467 *
1468 * const processValue = Match.type<string | number | null | undefined>()
1469 * .pipe(
1470 * Match.when(Match.defined, (value) => `Defined value: ${value}`),
1471 * Match.orElse(() => "Value is null or undefined")
1472 * )
1473 *
1474 * processValue("hello") // => "Defined value: hello"
1475 *
1476 * processValue(42) // => "Defined value: 42"
1477 *
1478 * processValue(0) // => "Defined value: 0"
1479 *
1480 * processValue("") // => "Defined value: "
1481 *
1482 * processValue(null) // => "Value is null or undefined"
1483 *
1484 * processValue(undefined) // => "Value is null or undefined"
1485 * ```
1486 *
1487 * @see {@link any} for matching every value without excluding nullish inputs
1488 *
1489 * @category guards
1490 * @since 4.0.0
1491 */
1492export const defined: <A>(u: A) => u is A & {} = internal.defined
1493
1494/**
1495 * Matches values of type `boolean`.
1496 *
1497 * **When to use**
1498 *
1499 * Use to match primitive boolean values.
1500 *
1501 * **Details**
1502 *
1503 * This predicate refines unknown values to booleans, allowing pattern matching
1504 * on boolean types. It only matches the primitive boolean values `true` and `false`.
1505 *
1506 * **Example** (Matching boolean values)
1507 *
1508 * ```ts import.meta.vitest
1509 * import { Match } from "effect"
1510 *
1511 * const describeTruthiness = Match.type<unknown>().pipe(
1512 * Match.when(
1513 * Match.boolean,
1514 * (bool) => bool ? "Definitely true" : "Definitely false"
1515 * ),
1516 * Match.when(0, () => "Falsy number"),
1517 * Match.when("", () => "Empty string"),
1518 * Match.when(Match.null, () => "Null value"),
1519 * Match.orElse(() => "Some other truthy value")
1520 * )
1521 *
1522 * describeTruthiness(true) // => "Definitely true"
1523 * describeTruthiness(false) // => "Definitely false"
1524 * describeTruthiness(0) // => "Falsy number"
1525 * describeTruthiness(1) // => "Some other truthy value"
1526 * ```
1527 *
1528 * @see {@link is} for matching specific literal boolean values
1529 *
1530 * @category guards
1531 * @since 4.0.0
1532 */
1533export const boolean: Predicate.Refinement<unknown, boolean> = Predicate.isBoolean
1534
1535const _undefined: Predicate.Refinement<unknown, undefined> = Predicate.isUndefined
1536export {
1537 /**
1538 * Matches the value `undefined`.
1539 *
1540 * **When to use**
1541 *
1542 * Use when a matcher should handle only inputs with no defined value.
1543 *
1544 * **Details**
1545 *
1546 * This refinement is backed by `Predicate.isUndefined`, which checks
1547 * `input === undefined`.
1548 *
1549 * @see {@link defined} for matching non-nullish values
1550 * @see {@link is} for matching literal values
1551 *
1552 * @category guards
1553 * @since 4.0.0
1554 */
1555 _undefined as undefined
1556}
1557
1558const _null: Predicate.Refinement<unknown, null> = Predicate.isNull
1559export {
1560 /**
1561 * Matches the value `null`.
1562 *
1563 * **When to use**
1564 *
1565 * Use to handle only the `null` literal in a match branch.
1566 *
1567 * **Details**
1568 *
1569 * This refinement is backed by `Predicate.isNull`, which checks
1570 * `input === null`.
1571 *
1572 * @see {@link defined} for matching non-nullish values
1573 * @see {@link is} for matching literal values
1574 *
1575 * @category guards
1576 * @since 4.0.0
1577 */
1578 _null as null
1579}
1580
1581/**
1582 * Matches values of type `bigint`.
1583 *
1584 * **When to use**
1585 *
1586 * Use to match primitive bigint values.
1587 *
1588 * **Details**
1589 *
1590 * This predicate refines unknown values to bigints, allowing pattern matching
1591 * on bigint types. BigInts are used for representing integers with arbitrary precision.
1592 *
1593 * **Example** (Matching bigint values)
1594 *
1595 * ```ts import.meta.vitest
1596 * import { Match } from "effect"
1597 *
1598 * const processLargeNumber = Match.type<unknown>().pipe(
1599 * Match.when(Match.bigint, (big) => {
1600 * if (big > 9007199254740991n) {
1601 * return `Large integer: ${big.toString()}`
1602 * }
1603 * return `BigInt: ${big.toString()}`
1604 * }),
1605 * Match.when(Match.number, (num) => `Regular number: ${num}`),
1606 * Match.orElse(() => "Not a numeric type")
1607 * )
1608 *
1609 * processLargeNumber(123n) // => "BigInt: 123"
1610 * processLargeNumber(9007199254740992n) // => "Large integer: 9007199254740992"
1611 * processLargeNumber(123) // => "Regular number: 123"
1612 * processLargeNumber("123") // => "Not a numeric type"
1613 * ```
1614 *
1615 * @see {@link number} for matching primitive number values
1616 *
1617 * @category guards
1618 * @since 4.0.0
1619 */
1620export const bigint: Predicate.Refinement<unknown, bigint> = Predicate.isBigInt
1621
1622/**
1623 * Matches values of type `symbol`.
1624 *
1625 * **Details**
1626 *
1627 * This predicate refines unknown values to symbols, allowing pattern matching
1628 * on symbol types. Symbols are unique identifiers that are often used as
1629 * object keys or for creating private properties.
1630 *
1631 * **Example** (Matching symbol values)
1632 *
1633 * ```ts import.meta.vitest
1634 * import { Match } from "effect"
1635 *
1636 * const mySymbol = Symbol("my-symbol")
1637 * const globalSymbol = Symbol.for("global-symbol")
1638 *
1639 * const handleSymbol = Match.type<unknown>().pipe(
1640 * Match.when(Match.symbol, (sym) => {
1641 * const description = sym.description
1642 * if (description) {
1643 * return `Symbol with description: ${description}`
1644 * }
1645 * return "Symbol without description"
1646 * }),
1647 * Match.orElse(() => "Not a symbol")
1648 * )
1649 *
1650 * handleSymbol(mySymbol) // => "Symbol with description: my-symbol"
1651 * handleSymbol(Symbol()) // => "Symbol without description"
1652 * handleSymbol("string") // => "Not a symbol"
1653 * ```
1654 *
1655 * @category guards
1656 * @since 4.0.0
1657 */
1658export const symbol: Predicate.Refinement<unknown, symbol> = Predicate.isSymbol
1659
1660/**
1661 * Matches values that are instances of `Date`.
1662 *
1663 * **When to use**
1664 *
1665 * Use to match `Date` instances.
1666 *
1667 * **Details**
1668 *
1669 * This predicate refines unknown values to Date instances, allowing pattern
1670 * matching on Date objects. It only matches actual Date instances, not
1671 * date strings or timestamps.
1672 *
1673 * **Example** (Matching Date instances)
1674 *
1675 * ```ts import.meta.vitest
1676 * import { Match } from "effect"
1677 *
1678 * const processDateValue = Match.type<unknown>().pipe(
1679 * Match.when(Match.date, (date) => {
1680 * if (isNaN(date.getTime())) {
1681 * return "Invalid date"
1682 * }
1683 * return `Date: ${date.toISOString().split("T")[0]}`
1684 * }),
1685 * Match.when(Match.string, (str) => `Date string: ${str}`),
1686 * Match.orElse(() => "Not a date-related value")
1687 * )
1688 *
1689 * processDateValue(new Date("2024-01-01")) // => "Date: 2024-01-01"
1690 * processDateValue(new Date("invalid")) // => "Invalid date"
1691 * processDateValue("2024-01-01") // => "Date string: 2024-01-01"
1692 * processDateValue(1704067200000) // => "Not a date-related value"
1693 * ```
1694 *
1695 * @see {@link instanceOf} for matching instances of any constructor
1696 *
1697 * @category guards
1698 * @since 4.0.0
1699 */
1700export const date: Predicate.Refinement<unknown, Date> = Predicate.isDate
1701
1702/**
1703 * Matches non-null objects other than arrays.
1704 *
1705 * **When to use**
1706 *
1707 * Use to match broad non-null, non-array object values.
1708 *
1709 * **Details**
1710 *
1711 * This predicate uses `Predicate.isObject`: it returns `true` for values whose
1712 * runtime type is `"object"`, are not `null`, and are not arrays. It can match
1713 * `Date`, `RegExp`, and class instances; use `instanceOf` or a more specific
1714 * pattern when those cases need to be distinguished.
1715 *
1716 * **Example** (Matching record objects)
1717 *
1718 * ```ts import.meta.vitest
1719 * import { Match } from "effect"
1720 *
1721 * const analyzeValue = Match.type<unknown>().pipe(
1722 * Match.when(Match.record, (obj) => {
1723 * const keys = Object.keys(obj)
1724 * const valueCount = keys.length
1725 * return `Object with ${valueCount} properties: [${keys.join(", ")}]`
1726 * }),
1727 * Match.when(
1728 * Match.instanceOf(Array),
1729 * (arr) => `Array with ${arr.length} items`
1730 * ),
1731 * Match.orElse(() => "Not an object")
1732 * )
1733 *
1734 * analyzeValue({ name: "Alice", age: 30 }) // => "Object with 2 properties: [name, age]"
1735 * analyzeValue([1, 2, 3]) // => "Array with 3 items"
1736 * analyzeValue(null) // => "Not an object"
1737 * analyzeValue("hello") // => "Not an object"
1738 * ```
1739 *
1740 * @see {@link instanceOf} for matching a specific constructor
1741 *
1742 * @category guards
1743 * @since 4.0.0
1744 */
1745export const record: Predicate.Refinement<unknown, { [x: PropertyKey]: unknown }> = Predicate.isObject
1746
1747/**
1748 * Matches instances of a given class.
1749 *
1750 * **When to use**
1751 *
1752 * Use to match values that are instances of a constructor with type-safe
1753 * narrowing.
1754 *
1755 * **Details**
1756 *
1757 * This predicate checks if a value is an instance of the specified constructor,
1758 * providing type-safe matching for class instances and built-in objects.
1759 *
1760 * **Example** (Matching class instances)
1761 *
1762 * ```ts import.meta.vitest
1763 * import { Match } from "effect"
1764 *
1765 * class CustomError extends Error {
1766 * constructor(message: string, public code: number) {
1767 * super(message)
1768 * }
1769 * }
1770 *
1771 * const handleValue = Match.type<unknown>()
1772 * .pipe(
1773 * Match.when(
1774 * Match.instanceOf(CustomError),
1775 * (err) => `Custom error: ${err.message} (code: ${err.code})`
1776 * ),
1777 * Match.when(
1778 * Match.instanceOf(Error),
1779 * (err) => `Standard error: ${err.message}`
1780 * ),
1781 * Match.when(
1782 * Match.instanceOf(Array),
1783 * (arr) => `Array with ${arr.length} items`
1784 * ),
1785 * Match.when(
1786 * Match.instanceOf(Map),
1787 * (map) => `Map with ${map.size} entries`
1788 * ),
1789 * Match.orElse((value) => `Other: ${typeof value}`)
1790 * )
1791 *
1792 * handleValue(new CustomError("Failed", 404)) // => "Custom error: Failed (code: 404)"
1793 * handleValue(new Error("Generic error")) // => "Standard error: Generic error"
1794 * handleValue([1, 2, 3]) // => "Array with 3 items"
1795 * handleValue(new Map([["count", 1]])) // => "Map with 1 entries"
1796 * ```
1797 *
1798 * @see {@link instanceOfUnsafe} for constructor matching without the same type-safety guarantee
1799 * @see {@link record} for matching broad non-null, non-array objects
1800 *
1801 * @category guards
1802 * @since 4.0.0
1803 */
1804export const instanceOf: <A extends abstract new(...args: any) => any>(
1805 constructor: A
1806) => SafeRefinement<InstanceType<A>, never> = internal.instanceOf
1807
1808/**
1809 * Checks whether a value is an instance of a constructor without type-safe narrowing.
1810 *
1811 * **When to use**
1812 *
1813 * Use when you need constructor matching to use the unsafe refinement type.
1814 *
1815 * **Details**
1816 *
1817 * This predicate checks if a value is an instance of the specified constructor
1818 * but doesn't provide the same type safety guarantees as the regular `instanceOf`.
1819 * Use this when you need more flexibility but understand the type safety implications.
1820 *
1821 * **Example** (Matching class instances unsafely)
1822 *
1823 * ```ts import.meta.vitest
1824 * import { Match } from "effect"
1825 *
1826 * class CustomError extends Error {
1827 * constructor(message: string, public code: number) {
1828 * super(message)
1829 * }
1830 * }
1831 *
1832 * // When you need to match instances but handle type narrowing manually
1833 * const handleError = Match.type<unknown>().pipe(
1834 * Match.when(Match.instanceOfUnsafe(CustomError), (err: any) => {
1835 * // Manual type assertion needed
1836 * const customErr = err as CustomError
1837 * return `Custom error ${customErr.code}: ${customErr.message}`
1838 * }),
1839 * Match.orElse(() => "Not a CustomError")
1840 * )
1841 * handleError(new CustomError("failed", 500)) // => "Custom error 500: failed"
1842 * ```
1843 *
1844 * @see {@link instanceOf} for type-safe constructor matching
1845 *
1846 * @category guards
1847 * @since 4.0.0
1848 */
1849export const instanceOfUnsafe: <A extends abstract new(...args: any) => any>(
1850 constructor: A
1851) => SafeRefinement<InstanceType<A>, InstanceType<A>> = internal.instanceOf
1852
1853/**
1854 * Provides a fallback value when no patterns match.
1855 *
1856 * **When to use**
1857 *
1858 * Use to finalize a matcher with a fallback for unmatched input.
1859 *
1860 * **Details**
1861 *
1862 * This function ensures that a matcher always returns a valid result, even if
1863 * no defined patterns match. It acts as a default case, similar to the
1864 * `default` clause in a `switch` statement or the final `else` in an `if-else`
1865 * chain.
1866 *
1867 * **Example** (Providing a default value when no patterns match)
1868 *
1869 * ```ts import.meta.vitest
1870 * import { Match } from "effect"
1871 *
1872 * // Create a matcher for string or number values
1873 * const match = Match.type<string | number>().pipe(
1874 * // Match when the value is "a"
1875 * Match.when("a", () => "ok"),
1876 * // Fallback when no patterns match
1877 * Match.orElse(() => "fallback")
1878 * )
1879 *
1880 * match("a") // => "ok"
1881 *
1882 * match("b") // => "fallback"
1883 * ```
1884 *
1885 * @see {@link option} for finalizing unmatched input as `Option.none`
1886 * @see {@link result} for returning unmatched input as a `Result` failure
1887 * @see {@link orElseAbsurd} for finalizing when unmatched input should be impossible
1888 *
1889 * @category completion
1890 * @since 4.0.0
1891 */
1892export const orElse: <RA, Ret, Args extends Array<any>, F extends (_: RA, ...args: Args) => Ret>(
1893 f: F
1894) => <I, R, A, Pr>(
1895 self: Matcher<I, R, RA, A, Pr, Ret, Args>
1896) => [Pr] extends [never] ? [Args] extends [[]] ? (input: I) => Unify<ReturnType<F> | A>
1897 : (...args: Args) => Unify<ReturnType<F> | A>
1898 : Unify<ReturnType<F> | A> = internal.orElse
1899
1900// TODO(4.0): Rename to "orThrow"? Like Result.getOrThrow
1901/**
1902 * Returns a matcher that throws an error if no pattern matches.
1903 *
1904 * **When to use**
1905 *
1906 * Use to finalize a matcher when every remaining unmatched case should be
1907 * impossible.
1908 *
1909 * **Details**
1910 *
1911 * This function finalizes a matcher by ensuring that if no patterns match, an
1912 * error is thrown. It is useful when all cases should be covered, and any
1913 * unexpected input should trigger an error instead of returning a default
1914 * value.
1915 *
1916 * When used, this function removes the need for an explicit fallback case and
1917 * ensures that an unmatched value is never silently ignored.
1918 *
1919 * **Example** (Throwing on unmatched input)
1920 *
1921 * ```ts import.meta.vitest
1922 * import { Match } from "effect"
1923 *
1924 * const strictMatcher = Match.type<"a" | "b">().pipe(
1925 * Match.when("a", () => "Found A"),
1926 * Match.when("b", () => "Found B"),
1927 * // Will throw if input is neither "a" nor "b"
1928 * Match.orElseAbsurd
1929 * )
1930 *
1931 * strictMatcher("a") // => "Found A"
1932 * strictMatcher("b") // => "Found B"
1933 *
1934 * // This would throw an error at runtime:
1935 * // strictMatcher("c" as any) // throws
1936 * ```
1937 *
1938 * @see {@link exhaustive} for compile-time exhaustive matcher finalization
1939 * @see {@link orElse} for providing a fallback for unmatched input
1940 *
1941 * @category completion
1942 * @since 4.0.0
1943 */
1944export const orElseAbsurd: <I, R, RA, A, Pr, Ret, Args extends Array<any>>(
1945 self: Matcher<I, R, RA, A, Pr, Ret, Args>
1946) => [Pr] extends [never] ? [Args] extends [[]] ? (input: I) => Unify<A> : (...args: Args) => Unify<A> : Unify<A> =
1947 internal.orElseAbsurd
1948
1949/**
1950 * Wraps the match result in a `Result`, distinguishing matched and unmatched
1951 * cases.
1952 *
1953 * **Details**
1954 *
1955 * This function ensures that the result of a matcher is always wrapped in an
1956 * `Result`, allowing clear differentiation between successful matches
1957 * (`Ok(value)`) and cases where no pattern matched (`Err(unmatched
1958 * value)`).
1959 *
1960 * This approach is particularly useful when handling optional values or when an
1961 * unmatched case should be explicitly handled rather than returning a default
1962 * value or throwing an error.
1963 *
1964 * **Example** (Extracting a user role with `Match.result`)
1965 *
1966 * ```ts import.meta.vitest
1967 * import { Match } from "effect"
1968 *
1969 * type User = { readonly role: "admin" | "editor" | "viewer" }
1970 *
1971 * // Create a matcher to extract user roles
1972 * const getRole = Match.type<User>().pipe(
1973 * Match.when({ role: "admin" }, () => "Has full access"),
1974 * Match.when({ role: "editor" }, () => "Can edit content"),
1975 * Match.result // Wrap the result in an Result
1976 * )
1977 *
1978 * getRole({ role: "admin" })._tag // => "Success"
1979 *
1980 * getRole({ role: "viewer" })._tag // => "Failure"
1981 * ```
1982 *
1983 * @category completion
1984 * @since 4.0.0
1985 */
1986export const result: <I, F, R, A, Pr, Ret, Args extends Array<any>>(
1987 self: Matcher<I, F, R, A, Pr, Ret, Args>
1988) => [Pr] extends [never] ? [Args] extends [[]] ? (input: I) => Result.Result<Unify<A>, R>
1989 : (...args: Args) => Result.Result<Unify<A>, R>
1990 : Result.Result<Unify<A>, R> = internal.result
1991
1992/**
1993 * Wraps the match result in an `Option`, representing an optional match.
1994 *
1995 * **When to use**
1996 *
1997 * Use to finalize a matcher when unmatched input is expected and should become
1998 * `Option.none`.
1999 *
2000 * **Details**
2001 *
2002 * This function ensures that the result of a matcher is wrapped in an `Option`,
2003 * making it easy to handle cases where no pattern matches. If a match is found,
2004 * it returns `Some(value)`, otherwise, it returns `None`.
2005 *
2006 * This is useful in cases where a missing match is expected and should be
2007 * handled explicitly rather than throwing an error or returning a default
2008 * value.
2009 *
2010 * **Example** (Extracting a user role with `Match.option`)
2011 *
2012 * ```ts import.meta.vitest
2013 * import { Match } from "effect"
2014 *
2015 * type User = { readonly role: "admin" | "editor" | "viewer" }
2016 *
2017 * // Create a matcher to extract user roles
2018 * const getRole = Match.type<User>().pipe(
2019 * Match.when({ role: "admin" }, () => "Has full access"),
2020 * Match.when({ role: "editor" }, () => "Can edit content"),
2021 * Match.option // Wrap the result in an Option
2022 * )
2023 *
2024 * getRole({ role: "admin" })._tag // => "Some"
2025 *
2026 * getRole({ role: "viewer" })._tag // => "None"
2027 * ```
2028 *
2029 * @see {@link result} for preserving unmatched input as a `Result` failure
2030 * @see {@link orElse} for replacing unmatched input with a fallback value
2031 *
2032 * @category completion
2033 * @since 4.0.0
2034 */
2035export const option: <I, F, R, A, Pr, Ret, Args extends Array<any>>(
2036 self: Matcher<I, F, R, A, Pr, Ret, Args>
2037) => [Pr] extends [never] ? [Args] extends [[]] ? (input: I) => Option.Option<Unify<A>>
2038 : (...args: Args) => Option.Option<Unify<A>>
2039 : Option.Option<Unify<A>> = internal.option
2040
2041/**
2042 * Completes a matcher that handles every remaining input case.
2043 *
2044 * **When to use**
2045 *
2046 * Use to require TypeScript to reject incomplete matcher definitions before the
2047 * matcher is turned into a function.
2048 *
2049 * **Details**
2050 *
2051 * If any case is still unmatched, the matcher does not type-check as
2052 * exhaustive.
2053 *
2054 * **Example** (Ensuring all cases are covered)
2055 *
2056 * ```ts import.meta.vitest
2057 * import { Match } from "effect"
2058 *
2059 * // Create a matcher for string or number values
2060 * const match = Match.type<string | number>().pipe(
2061 * // Match when the value is a number
2062 * Match.when(Match.number, (n) => `number: ${n}`),
2063 * // Mark the match as exhaustive, ensuring all cases are handled
2064 * // TypeScript will throw an error if any case is missing
2065 * // @ts-expect-error Type 'string' is not assignable to type 'never'
2066 * Match.exhaustive
2067 * )
2068 * ```
2069 *
2070 * @category completion
2071 * @since 4.0.0
2072 */
2073export const exhaustive: <I, F, A, Pr, Ret, Args extends Array<any>>(
2074 self: Matcher<I, F, never, A, Pr, Ret, Args>
2075) => [Pr] extends [never] ? [Args] extends [[]] ? (u: I) => Unify<A> : (...args: Args) => Unify<A> : Unify<A> =
2076 internal.exhaustive
2077
2078const SafeRefinementId = "~effect/Match/SafeRefinement"
2079
2080/**
2081 * A safe refinement that narrows types without runtime errors.
2082 *
2083 * **Details**
2084 *
2085 * `SafeRefinement` provides a way to refine types in pattern matching while
2086 * maintaining type safety. Unlike regular predicates, safe refinements can
2087 * transform the matched value's type without throwing runtime errors.
2088 *
2089 * **Example** (Using safe refinements)
2090 *
2091 * ```ts import.meta.vitest
2092 * import { Match } from "effect"
2093 *
2094 * // Built-in safe refinements
2095 * const processValue = Match.type<unknown>().pipe(
2096 * Match.when(Match.string, (s) => s.toUpperCase()),
2097 * Match.when(Match.number, (n) => n * 2),
2098 * Match.when(Match.defined, (value) => `Defined: ${value}`),
2099 * Match.orElse(() => "Undefined or null")
2100 * )
2101 *
2102 * processValue("hello") // => "HELLO"
2103 * processValue(21) // => 42
2104 * processValue(true) // => "Defined: true"
2105 * processValue(null) // => "Undefined or null"
2106 * ```
2107 *
2108 * @category models
2109 * @since 4.0.0
2110 */
2111export interface SafeRefinement<in A, out R = A> {
2112 readonly [SafeRefinementId]: (a: A) => R
2113}
2114
2115const Fail = Symbol.for("effect/Fail")
2116type Fail = typeof Fail
2117
2118/**
2119 * A namespace containing utility types for Match operations.
2120 *
2121 * **Details**
2122 *
2123 * This namespace provides advanced type-level utilities used internally by the
2124 * Match module to perform complex pattern matching, type narrowing, and filter
2125 * application. These types enable the sophisticated type inference that makes
2126 * pattern matching both type-safe and ergonomic.
2127 *
2128 * @since 4.0.0
2129 */
2130export declare namespace Types {
2131 /**
2132 * Computes the matched type when a pattern P is applied to type R.
2133 *
2134 * **Details**
2135 *
2136 * This utility type determines what type a value will have after successfully
2137 * matching against a pattern. It handles refinements, predicates, and complex
2138 * object patterns to provide accurate type narrowing.
2139 *
2140 * **Example** (Computing matched types)
2141 *
2142 * ```ts import.meta.vitest
2143 * import type { Match } from "effect"
2144 *
2145 * // WhenMatch computes the narrowed type after pattern matching
2146 * type StringMatch = Match.Types.WhenMatch<string | number, typeof Match.string>
2147 * // Result: string
2148 *
2149 * type ObjectMatch = Match.Types.WhenMatch<
2150 * { type: "user"; name: string } | {
2151 * type: "admin"
2152 * permissions: Array<string>
2153 * },
2154 * { type: "user" }
2155 * >
2156 * // Result: { type: "user"; name: string }
2157 * ```
2158 *
2159 * @category utility types
2160 * @since 4.0.0
2161 */
2162 export type WhenMatch<R, P> =
2163 // check for any
2164 [0] extends [1 & R] ? ResolvePred<P> :
2165 P extends SafeRefinement<infer SP, never> ? SP
2166 : P extends Predicate.Refinement<infer _R, infer RP>
2167 // try to narrow refinement
2168 ? [Extract<R, RP>] extends [infer X] ? [X] extends [never]
2169 // fallback to original refinement
2170 ? RP
2171 : X
2172 : never
2173 : P extends PredicateA<infer PP> ? PP
2174 : ExtractMatch<R, P>
2175
2176 /**
2177 * Computes the remaining type when a pattern P is excluded from type R.
2178 *
2179 * **Details**
2180 *
2181 * This utility type determines what type remains after a `Match.not` pattern
2182 * excludes certain values. It's the complement of `WhenMatch`, calculating
2183 * what's left after removing the matched portion.
2184 *
2185 * **Example** (Computing unmatched types)
2186 *
2187 * ```ts import.meta.vitest
2188 * import type { Match } from "effect"
2189 *
2190 * // NotMatch computes what remains after exclusion
2191 * type NotString = Match.Types.NotMatch<
2192 * string | number | boolean,
2193 * typeof Match.string
2194 * >
2195 * // Result: number | boolean
2196 *
2197 * type NotSpecificValue = Match.Types.NotMatch<"a" | "b" | "c", "a">
2198 * // Result: "b" | "c"
2199 * ```
2200 *
2201 * @category utility types
2202 * @since 4.0.0
2203 */
2204 export type NotMatch<R, P> = Exclude<R, ExtractMatch<R, PForNotMatch<P>>>
2205
2206 type PForNotMatch<P> = [ToInvertedRefinement<P>] extends [infer X] ? X
2207 : never
2208
2209 /**
2210 * Resolves a pattern to its matched type for use in type computations.
2211 *
2212 * **Details**
2213 *
2214 * This utility type processes patterns (predicates, refinements, objects)
2215 * and resolves them to their corresponding matched types. It's used internally
2216 * to compute type transformations during pattern matching.
2217 *
2218 * **Example** (Resolving match patterns)
2219 *
2220 * ```ts import.meta.vitest
2221 * import type { Match } from "effect"
2222 *
2223 * // PForMatch resolves patterns to their matched types
2224 * type StringPattern = Match.Types.PForMatch<typeof Match.string>
2225 * // Result: string
2226 *
2227 * type ObjectPattern = Match.Types.PForMatch<{ name: string }>
2228 * // Result: { name: string }
2229 * ```
2230 *
2231 * @category utility types
2232 * @since 4.0.0
2233 */
2234 export type PForMatch<P> = [ResolvePred<P>] extends [infer X] ? X
2235 : never
2236
2237 /**
2238 * Computes the excluded type when a pattern P is used for exclusion.
2239 *
2240 * **Details**
2241 *
2242 * This utility type determines what should be excluded from a union type
2243 * when a pattern is used in filtering operations. It transforms patterns
2244 * into their exclusion-safe representations.
2245 *
2246 * **Example** (Computing excluded patterns)
2247 *
2248 * ```ts import.meta.vitest
2249 * import type { Match } from "effect"
2250 *
2251 * // PForExclude computes what to exclude from type operations
2252 * type ExcludeString = Match.Types.PForExclude<typeof Match.string>
2253 * // Used internally to filter out string types
2254 *
2255 * type ExcludeObject = Match.Types.PForExclude<{ type: "admin" }>
2256 * // Used internally to filter out admin objects
2257 * ```
2258 *
2259 * @category utility types
2260 * @since 4.0.0
2261 */
2262 export type PForExclude<P> = [SafeRefinementR<ToSafeRefinement<P>>] extends [infer X] ? X
2263 : never
2264
2265 // utilities
2266 type PredicateA<A> = Predicate.Predicate<A> | Predicate.Refinement<A, A>
2267
2268 type SafeRefinementR<A> = A extends never ? never
2269 : A extends SafeRefinement<infer _, infer R> ? R
2270 : A extends Function ? A
2271 : A extends Record<string, any> ? { [K in keyof A]: SafeRefinementR<A[K]> }
2272 : A
2273
2274 type ResolvePred<A, Input = any> = A extends never ? never
2275 : A extends SafeRefinement<infer _A, infer _R> ? _A
2276 : A extends Predicate.Refinement<Input, infer P> ? P
2277 : A extends Predicate.Predicate<infer P> ? P
2278 : A extends Record<string, any> ? { [K in keyof A]: ResolvePred<A[K]> }
2279 : A
2280
2281 type ToSafeRefinement<A> = A extends never ? never
2282 : A extends Predicate.Refinement<any, infer P> ? SafeRefinement<P, P>
2283 : A extends Predicate.Predicate<infer P> ? SafeRefinement<P, never>
2284 : A extends SafeRefinement<any> ? A
2285 : A extends Record<string, any> ? { [K in keyof A]: ToSafeRefinement<A[K]> }
2286 : NonLiteralsTo<A, never>
2287
2288 type ToInvertedRefinement<A> = A extends never ? never
2289 : A extends Predicate.Refinement<any, infer P> ? SafeRefinement<P>
2290 : A extends Predicate.Predicate<infer _P> ? SafeRefinement<never>
2291 : A extends SafeRefinement<infer _A, infer _R> ? SafeRefinement<_R>
2292 : A extends Record<string, any> ? { [K in keyof A]: ToInvertedRefinement<A[K]> }
2293 : NonLiteralsTo<A, never>
2294
2295 type NonLiteralsTo<A, T> = [A] extends [string | number | boolean | bigint] ? [string] extends [A] ? T
2296 : [number] extends [A] ? T
2297 : [boolean] extends [A] ? T
2298 : [bigint] extends [A] ? T
2299 : A
2300 : A
2301
2302 /**
2303 * Defines the structure for complex object and array patterns.
2304 *
2305 * **Details**
2306 *
2307 * This type represents patterns that can match against complex data structures
2308 * like objects and arrays. It supports nested pattern matching and partial
2309 * object matching, enabling sophisticated pattern compositions.
2310 *
2311 * **Example** (Describing complex object patterns)
2312 *
2313 * ```ts import.meta.vitest
2314 * import { Match } from "effect"
2315 *
2316 * // PatternBase enables complex object patterns
2317 * type UserPattern = Match.Types.PatternBase<{
2318 * name: string
2319 * age: number
2320 * role: "admin" | "user"
2321 * }>
2322 * // Allows: { name?: string | Predicate, age?: number | Predicate, ... }
2323 *
2324 * // Example usage:
2325 * const result = Match.value({ name: "Alice", age: 30, role: "admin" as const }).pipe(
2326 * Match.when(
2327 * { age: (n: number) => n >= 18, role: "admin" },
2328 * (user: { name: string; age: number; role: "admin" }) =>
2329 * `Admin: ${user.name}`
2330 * ),
2331 * Match.orElse(() => "Not an adult admin")
2332 * )
2333 * result // => "Admin: Alice"
2334 * ```
2335 *
2336 * @category utility types
2337 * @since 4.0.0
2338 */
2339 export type PatternBase<A> = A extends ReadonlyArray<infer _T> ? ReadonlyArray<any> | PatternPrimitive<A>
2340 : A extends Record<string, any> ? Partial<
2341 { [K in keyof A]: PatternPrimitive<A[K] & {}> | PatternBase<A[K] & {}> }
2342 >
2343 : never
2344
2345 /**
2346 * Defines primitive patterns that can match simple values.
2347 *
2348 * **Details**
2349 *
2350 * This type represents the building blocks of pattern matching: predicates,
2351 * literal values, and safe refinements. These are the atomic patterns that
2352 * can be composed into more complex matching logic.
2353 *
2354 * @category utility types
2355 * @since 4.0.0
2356 */
2357 export type PatternPrimitive<A> = PredicateA<A> | A | SafeRefinement<any>
2358
2359 /**
2360 * Represents a filter that excludes specific types from a union.
2361 *
2362 * **Details**
2363 *
2364 * `Without` is used internally to track which types should be excluded
2365 * from consideration during pattern matching. It helps implement the
2366 * type-level logic for `Match.not` and other exclusion operations.
2367 *
2368 * **Example** (Tracking excluded types)
2369 *
2370 * ```ts import.meta.vitest
2371 * import { Match } from "effect"
2372 *
2373 * // Without is used internally when you write:
2374 * const match = Match.type<string | number | boolean>().pipe(
2375 * Match.not(Match.string, (value) => `not string: ${value}`),
2376 * // At this point, type system uses Without<string> to track exclusion
2377 * Match.orElse(() => "was a string")
2378 * )
2379 * match(42) // => "not string: 42"
2380 * ```
2381 *
2382 * @category utility types
2383 * @since 4.0.0
2384 */
2385 export interface Without<out X> {
2386 readonly _tag: "Without"
2387 readonly _X: X
2388 }
2389
2390 /**
2391 * Represents a filter that includes only specific types from a union.
2392 *
2393 * **Details**
2394 *
2395 * `Only` is used internally to track which types should be exclusively
2396 * considered during pattern matching. It helps implement the type-level
2397 * logic for positive matches and type narrowing.
2398 *
2399 * **Example** (Tracking included types)
2400 *
2401 * ```ts import.meta.vitest
2402 * import { Match } from "effect"
2403 *
2404 * // Only is used internally when you write:
2405 * const match = Match.type<string | number | boolean>().pipe(
2406 * Match.when(Match.string, (s) => `string: ${s}`),
2407 * // At this point, type system uses Only<string> for the match
2408 * Match.orElse((value) => `not string: ${value}`)
2409 * )
2410 * match("ok") // => "string: ok"
2411 * ```
2412 *
2413 * @category utility types
2414 * @since 4.0.0
2415 */
2416 export interface Only<out X> {
2417 readonly _tag: "Only"
2418 readonly _X: X
2419 }
2420
2421 /**
2422 * Adds a type to the exclusion filter, expanding what should be filtered out.
2423 *
2424 * **Details**
2425 *
2426 * This utility type manages the accumulation of excluded types during
2427 * pattern matching. When multiple exclusions are applied, it combines
2428 * them into a single filter representation.
2429 *
2430 * **Example** (Accumulating excluded types)
2431 *
2432 * ```ts import.meta.vitest
2433 * import { Match } from "effect"
2434 *
2435 * // AddWithout is used when combining multiple exclusions:
2436 * const match = Match.type<string | number | boolean | null>().pipe(
2437 * Match.not(Match.string, () => "not string"),
2438 * Match.not(Match.number, () => "not number"),
2439 * // Type system uses AddWithout to combine exclusions
2440 * Match.orElse(() => "was string or number")
2441 * )
2442 * match(true) // => "not string"
2443 * ```
2444 *
2445 * @category utility types
2446 * @since 4.0.0
2447 */
2448 export type AddWithout<A, X> = [A] extends [Without<infer WX>] ? Without<X | WX>
2449 : [A] extends [Only<infer OX>] ? Only<Exclude<OX, X>>
2450 : never
2451
2452 /**
2453 * Adds a type to the inclusion filter, refining what should be included.
2454 *
2455 * **Details**
2456 *
2457 * This utility type manages the refinement of included types during
2458 * pattern matching. It ensures that only the most specific type
2459 * constraints are maintained when multiple positive matches are applied.
2460 *
2461 * **Example** (Refining included types)
2462 *
2463 * ```ts import.meta.vitest
2464 * import { Match } from "effect"
2465 *
2466 * // AddOnly is used when refining positive matches:
2467 * const match = Match.type<{ type: "user" | "admin"; name: string }>().pipe(
2468 * Match.when({ type: "admin" }, (admin) => admin.name),
2469 * // Type system uses AddOnly to refine the constraint
2470 * Match.orElse(() => "not admin")
2471 * )
2472 * match({ type: "admin", name: "Alice" }) // => "Alice"
2473 * ```
2474 *
2475 * @category utility types
2476 * @since 4.0.0
2477 */
2478 export type AddOnly<A, X> = [A] extends [Without<infer WX>] ? [X] extends [WX] ? never
2479 : Only<X>
2480 : [A] extends [Only<infer OX>] ? [X] extends [OX] ? Only<X>
2481 : never
2482 : never
2483
2484 /**
2485 * Applies accumulated filters to an input type, producing the final narrowed type.
2486 *
2487 * **Details**
2488 *
2489 * This utility type takes the collected inclusion/exclusion filters and
2490 * applies them to the input type to compute the final narrowed result.
2491 * It's the culmination of the type-level filtering process.
2492 *
2493 * **Example** (Applying accumulated filters)
2494 *
2495 * ```ts import.meta.vitest
2496 * import type { Match } from "effect"
2497 *
2498 * // ApplyFilters computes the final narrowed type:
2499 * type Result = Match.Types.ApplyFilters<
2500 * string | number | boolean,
2501 * Match.Types.Only<string>
2502 * >
2503 * // Result: string
2504 *
2505 * type ExclusionResult = Match.Types.ApplyFilters<
2506 * string | number | boolean,
2507 * Match.Types.Without<string>
2508 * >
2509 * // Result: number | boolean
2510 * ```
2511 *
2512 * @category utility types
2513 * @since 4.0.0
2514 */
2515 export type ApplyFilters<I, A> = A extends Only<infer X> ? X
2516 : A extends Without<infer X> ? Exclude<I, X>
2517 : never
2518
2519 /**
2520 * Extracts tag values from a discriminated union based on a discriminant field.
2521 *
2522 * **Details**
2523 *
2524 * This utility type extracts the possible values of a discriminant field
2525 * from a union type. It's used internally to implement tag-based pattern
2526 * matching for discriminated unions.
2527 *
2528 * **Example** (Extracting discriminator tags)
2529 *
2530 * ```ts import.meta.vitest
2531 * import type { Match } from "effect"
2532 *
2533 * type Events =
2534 * | { _tag: "click"; x: number; y: number }
2535 * | { _tag: "keypress"; key: string }
2536 * | { _tag: "scroll"; delta: number }
2537 *
2538 * type EventTags = Match.Types.Tags<"_tag", Events>
2539 * // Result: "click" | "keypress" | "scroll"
2540 *
2541 * type CustomTags = Match.Types.Tags<
2542 * "type",
2543 * | { type: "user"; name: string }
2544 * | { type: "admin"; permissions: Array<string> }
2545 * >
2546 * // Result: "user" | "admin"
2547 * ```
2548 *
2549 * @category utility types
2550 * @since 4.0.0
2551 */
2552 export type Tags<D extends string, P> = P extends Record<D, infer X> ? X : never
2553
2554 /**
2555 * Converts an array type to an intersection of its element types.
2556 *
2557 * **Details**
2558 *
2559 * This utility type takes an array of types and converts them into a single
2560 * intersection type. It's used internally when multiple patterns need to
2561 * be satisfied simultaneously (like in `Match.whenAnd`).
2562 *
2563 * **Example** (Converting arrays to intersections)
2564 *
2565 * ```ts import.meta.vitest
2566 * import type { Match } from "effect"
2567 *
2568 * type Combined = Match.Types.ArrayToIntersection<[
2569 * { name: string },
2570 * { age: number },
2571 * { active: boolean }
2572 * ]>
2573 * // Result: { name: string } & { age: number } & { active: boolean }
2574 * // = { name: string; age: number; active: boolean }
2575 *
2576 * // This type utility enables complex type intersections
2577 * // Complex type operations are handled by this utility type
2578 * // for advanced pattern matching scenarios
2579 * ```
2580 *
2581 * @category utility types
2582 * @since 4.0.0
2583 */
2584 export type ArrayToIntersection<A extends ReadonlyArray<any>> = T.UnionToIntersection<
2585 A[number]
2586 >
2587
2588 /**
2589 * Extracts and narrows the matched type from an input type given a pattern.
2590 *
2591 * **Details**
2592 *
2593 * This is the core type utility that performs the actual type extraction
2594 * and narrowing logic. It handles the complex type-level computation that
2595 * determines what type results from applying a pattern to an input type.
2596 *
2597 * **Example** (Extracting matched types)
2598 *
2599 * ```ts import.meta.vitest
2600 * import { Match } from "effect"
2601 *
2602 * type StringExtract = Match.Types.ExtractMatch<
2603 * string | number | boolean,
2604 * typeof Match.string
2605 * >
2606 * // Result: string
2607 *
2608 * type ObjectExtract = Match.Types.ExtractMatch<
2609 * { type: "user"; name: string } | { type: "admin"; role: string },
2610 * { type: "user" }
2611 * >
2612 * // Result: { type: "user"; name: string }
2613 *
2614 * // This powers the type narrowing in:
2615 * Match.when(Match.string, (s) => s.toUpperCase())
2616 * // ^^^ s is correctly typed as string
2617 * ```
2618 *
2619 * @category utility types
2620 * @since 4.0.0
2621 */
2622 export type ExtractMatch<I, P> = [ExtractAndNarrow<I, P>] extends [infer EI] ? EI
2623 : never
2624
2625 type Replace<A, B> = A extends Function ? A
2626 : A extends Record<string | number, any> ? { [K in keyof A]: K extends keyof B ? Replace<A[K], B[K]> : A[K] }
2627 : [B] extends [A] ? B
2628 : A
2629
2630 type MaybeReplace<I, P> = [P] extends [I] ? P
2631 : [I] extends [P] ? Replace<I, P>
2632 : Fail
2633
2634 type BuiltInObjects =
2635 | Function
2636 | Date
2637 | RegExp
2638 | Generator
2639 | { readonly [Symbol.toStringTag]: string }
2640
2641 type IsPlainObject<T> = T extends BuiltInObjects ? false
2642 : T extends Record<string, any> ? true
2643 : false
2644
2645 type Simplify<A> = { [K in keyof A]: A[K] } & {}
2646
2647 type ExtractAndNarrow<Input, P> = P extends Predicate.Refinement<infer _In, infer _Out> ?
2648 _Out extends Input ? Extract<_Out, Input>
2649 : Extract<Input, _Out> :
2650 P extends SafeRefinement<infer _In, infer _R> ? [0] extends [1 & _R] ? Input
2651 : _In extends Input ? Extract<_In, Input>
2652 : Extract<Input, _In>
2653 : P extends Predicate.Predicate<infer _In> ? Extract<Input, _In>
2654 : Input extends infer I ? Exclude<
2655 I extends ReadonlyArray<any> ? P extends ReadonlyArray<any> ? {
2656 readonly [K in keyof I]: K extends keyof P ? ExtractAndNarrow<I[K], P[K]>
2657 : I[K]
2658 } extends infer R ? Fail extends R[keyof R] ? never
2659 : R
2660 : never
2661 : never
2662 : IsPlainObject<I> extends true ? string extends keyof I ? I extends P ? I
2663 : never
2664 : symbol extends keyof I ? I extends P ? I
2665 : never
2666 : Simplify<
2667 & { [RK in Extract<keyof I, keyof P>]-?: ExtractAndNarrow<I[RK], P[RK]> }
2668 & Omit<I, keyof P>
2669 > extends infer R ? keyof P extends NonFailKeys<R> ? R
2670 : never
2671 : never
2672 : MaybeReplace<I, P> extends infer R ? [I] extends [R] ? I
2673 : R
2674 : never,
2675 Fail
2676 > :
2677 never
2678
2679 type NonFailKeys<A> = keyof A & {} extends infer K ? K extends keyof A ? A[K] extends Fail ? never : K
2680 : never :
2681 never
2682}