Hyperlinkv0.8.0-beta.28

Match

Match.Typesnamespaceeffect/Match.ts:2059
any

A namespace containing utility types for Match operations.

Details

This namespace provides advanced type-level utilities used internally by the Match module to perform complex pattern matching, type narrowing, and filter application. These types enable the sophisticated type inference that makes pattern matching both type-safe and ergonomic.

Source effect/Match.ts:2059548 lines
export declare namespace Types {
  /**
   * Computes the matched type when a pattern P is applied to type R.
   *
   * **Details**
   *
   * This utility type determines what type a value will have after successfully
   * matching against a pattern. It handles refinements, predicates, and complex
   * object patterns to provide accurate type narrowing.
   *
   * **Example** (Computing matched types)
   *
   * ```ts
   * import type { Match } from "effect"
   *
   * // WhenMatch computes the narrowed type after pattern matching
   * type StringMatch = Match.Types.WhenMatch<string | number, typeof Match.string>
   * // Result: string
   *
   * type ObjectMatch = Match.Types.WhenMatch<
   *   { type: "user"; name: string } | {
   *     type: "admin"
   *     permissions: Array<string>
   *   },
   *   { type: "user" }
   * >
   * // Result: { type: "user"; name: string }
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export type WhenMatch<R, P> =
    // check for any
    [0] extends [1 & R] ? ResolvePred<P> :
      P extends SafeRefinement<infer SP, never> ? SP
      : P extends Predicate.Refinement<infer _R, infer RP>
      // try to narrow refinement
        ? [Extract<R, RP>] extends [infer X] ? [X] extends [never]
            // fallback to original refinement
            ? RP
          : X
        : never
      : P extends PredicateA<infer PP> ? PP
      : ExtractMatch<R, P>

  /**
   * Computes the remaining type when a pattern P is excluded from type R.
   *
   * **Details**
   *
   * This utility type determines what type remains after a `Match.not` pattern
   * excludes certain values. It's the complement of `WhenMatch`, calculating
   * what's left after removing the matched portion.
   *
   * **Example** (Computing unmatched types)
   *
   * ```ts
   * import type { Match } from "effect"
   *
   * // NotMatch computes what remains after exclusion
   * type NotString = Match.Types.NotMatch<
   *   string | number | boolean,
   *   typeof Match.string
   * >
   * // Result: number | boolean
   *
   * type NotSpecificValue = Match.Types.NotMatch<"a" | "b" | "c", "a">
   * // Result: "b" | "c"
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export type NotMatch<R, P> = Exclude<R, ExtractMatch<R, PForNotMatch<P>>>

  type PForNotMatch<P> = [ToInvertedRefinement<P>] extends [infer X] ? X
    : never

  /**
   * Resolves a pattern to its matched type for use in type computations.
   *
   * **Details**
   *
   * This utility type processes patterns (predicates, refinements, objects)
   * and resolves them to their corresponding matched types. It's used internally
   * to compute type transformations during pattern matching.
   *
   * **Example** (Resolving match patterns)
   *
   * ```ts
   * import type { Match } from "effect"
   *
   * // PForMatch resolves patterns to their matched types
   * type StringPattern = Match.Types.PForMatch<typeof Match.string>
   * // Result: string
   *
   * type ObjectPattern = Match.Types.PForMatch<{ name: string }>
   * // Result: { name: string }
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export type PForMatch<P> = [ResolvePred<P>] extends [infer X] ? X
    : never

  /**
   * Computes the excluded type when a pattern P is used for exclusion.
   *
   * **Details**
   *
   * This utility type determines what should be excluded from a union type
   * when a pattern is used in filtering operations. It transforms patterns
   * into their exclusion-safe representations.
   *
   * **Example** (Computing excluded patterns)
   *
   * ```ts
   * import type { Match } from "effect"
   *
   * // PForExclude computes what to exclude from type operations
   * type ExcludeString = Match.Types.PForExclude<typeof Match.string>
   * // Used internally to filter out string types
   *
   * type ExcludeObject = Match.Types.PForExclude<{ type: "admin" }>
   * // Used internally to filter out admin objects
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export type PForExclude<P> = [SafeRefinementR<ToSafeRefinement<P>>] extends [infer X] ? X
    : never

  // utilities
  type PredicateA<A> = Predicate.Predicate<A> | Predicate.Refinement<A, A>

  type SafeRefinementR<A> = A extends never ? never
    : A extends SafeRefinement<infer _, infer R> ? R
    : A extends Function ? A
    : A extends Record<string, any> ? { [K in keyof A]: SafeRefinementR<A[K]> }
    : A

  type ResolvePred<A, Input = any> = A extends never ? never
    : A extends SafeRefinement<infer _A, infer _R> ? _A
    : A extends Predicate.Refinement<Input, infer P> ? P
    : A extends Predicate.Predicate<infer P> ? P
    : A extends Record<string, any> ? { [K in keyof A]: ResolvePred<A[K]> }
    : A

  type ToSafeRefinement<A> = A extends never ? never
    : A extends Predicate.Refinement<any, infer P> ? SafeRefinement<P, P>
    : A extends Predicate.Predicate<infer P> ? SafeRefinement<P, never>
    : A extends SafeRefinement<any> ? A
    : A extends Record<string, any> ? { [K in keyof A]: ToSafeRefinement<A[K]> }
    : NonLiteralsTo<A, never>

  type ToInvertedRefinement<A> = A extends never ? never
    : A extends Predicate.Refinement<any, infer P> ? SafeRefinement<P>
    : A extends Predicate.Predicate<infer _P> ? SafeRefinement<never>
    : A extends SafeRefinement<infer _A, infer _R> ? SafeRefinement<_R>
    : A extends Record<string, any> ? { [K in keyof A]: ToInvertedRefinement<A[K]> }
    : NonLiteralsTo<A, never>

  type NonLiteralsTo<A, T> = [A] extends [string | number | boolean | bigint] ? [string] extends [A] ? T
    : [number] extends [A] ? T
    : [boolean] extends [A] ? T
    : [bigint] extends [A] ? T
    : A
    : A

  /**
   * Defines the structure for complex object and array patterns.
   *
   * **Details**
   *
   * This type represents patterns that can match against complex data structures
   * like objects and arrays. It supports nested pattern matching and partial
   * object matching, enabling sophisticated pattern compositions.
   *
   * **Example** (Describing complex object patterns)
   *
   * ```ts
   * import { Match } from "effect"
   *
   * // PatternBase enables complex object patterns
   * type UserPattern = Match.Types.PatternBase<{
   *   name: string
   *   age: number
   *   role: "admin" | "user"
   * }>
   * // Allows: { name?: string | Predicate, age?: number | Predicate, ... }
   *
   * // Example usage:
   * Match.value({ name: "Alice", age: 30, role: "admin" as const }).pipe(
   *   Match.when(
   *     { age: (n: number) => n >= 18, role: "admin" },
   *     (user: { name: string; age: number; role: "admin" }) =>
   *       `Admin: ${user.name}`
   *   ),
   *   Match.orElse(() => "Not an adult admin")
   * )
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export type PatternBase<A> = A extends ReadonlyArray<infer _T> ? ReadonlyArray<any> | PatternPrimitive<A>
    : A extends Record<string, any> ? Partial<
        { [K in keyof A]: PatternPrimitive<A[K] & {}> | PatternBase<A[K] & {}> }
      >
    : never

  /**
   * Defines primitive patterns that can match simple values.
   *
   * **Details**
   *
   * This type represents the building blocks of pattern matching: predicates,
   * literal values, and safe refinements. These are the atomic patterns that
   * can be composed into more complex matching logic.
   *
   * @category types
   * @since 4.0.0
   */
  export type PatternPrimitive<A> = PredicateA<A> | A | SafeRefinement<any>

  /**
   * Represents a filter that excludes specific types from a union.
   *
   * **Details**
   *
   * `Without` is used internally to track which types should be excluded
   * from consideration during pattern matching. It helps implement the
   * type-level logic for `Match.not` and other exclusion operations.
   *
   * **Example** (Tracking excluded types)
   *
   * ```ts
   * import { Match } from "effect"
   *
   * // Without is used internally when you write:
   * Match.type<string | number | boolean>().pipe(
   *   Match.not(Match.string, (value) => `not string: ${value}`),
   *   // At this point, type system uses Without<string> to track exclusion
   *   Match.orElse(() => "was a string")
   * )
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export interface Without<out X> {
    readonly _tag: "Without"
    readonly _X: X
  }

  /**
   * Represents a filter that includes only specific types from a union.
   *
   * **Details**
   *
   * `Only` is used internally to track which types should be exclusively
   * considered during pattern matching. It helps implement the type-level
   * logic for positive matches and type narrowing.
   *
   * **Example** (Tracking included types)
   *
   * ```ts
   * import { Match } from "effect"
   *
   * // Only is used internally when you write:
   * Match.type<string | number | boolean>().pipe(
   *   Match.when(Match.string, (s) => `string: ${s}`),
   *   // At this point, type system uses Only<string> for the match
   *   Match.orElse((value) => `not string: ${value}`)
   * )
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export interface Only<out X> {
    readonly _tag: "Only"
    readonly _X: X
  }

  /**
   * Adds a type to the exclusion filter, expanding what should be filtered out.
   *
   * **Details**
   *
   * This utility type manages the accumulation of excluded types during
   * pattern matching. When multiple exclusions are applied, it combines
   * them into a single filter representation.
   *
   * **Example** (Accumulating excluded types)
   *
   * ```ts
   * import { Match } from "effect"
   *
   * // AddWithout is used when combining multiple exclusions:
   * Match.type<string | number | boolean | null>().pipe(
   *   Match.not(Match.string, () => "not string"),
   *   Match.not(Match.number, () => "not number"),
   *   // Type system uses AddWithout to combine exclusions
   *   Match.orElse(() => "was string or number")
   * )
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export type AddWithout<A, X> = [A] extends [Without<infer WX>] ? Without<X | WX>
    : [A] extends [Only<infer OX>] ? Only<Exclude<OX, X>>
    : never

  /**
   * Adds a type to the inclusion filter, refining what should be included.
   *
   * **Details**
   *
   * This utility type manages the refinement of included types during
   * pattern matching. It ensures that only the most specific type
   * constraints are maintained when multiple positive matches are applied.
   *
   * **Example** (Refining included types)
   *
   * ```ts
   * import { Match } from "effect"
   *
   * // AddOnly is used when refining positive matches:
   * Match.type<{ type: "user" | "admin"; name: string }>().pipe(
   *   Match.when({ type: "admin" }, (admin) => admin.name),
   *   // Type system uses AddOnly to refine the constraint
   *   Match.orElse(() => "not admin")
   * )
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export type AddOnly<A, X> = [A] extends [Without<infer WX>] ? [X] extends [WX] ? never
    : Only<X>
    : [A] extends [Only<infer OX>] ? [X] extends [OX] ? Only<X>
      : never
    : never

  /**
   * Applies accumulated filters to an input type, producing the final narrowed type.
   *
   * **Details**
   *
   * This utility type takes the collected inclusion/exclusion filters and
   * applies them to the input type to compute the final narrowed result.
   * It's the culmination of the type-level filtering process.
   *
   * **Example** (Applying accumulated filters)
   *
   * ```ts
   * import type { Match } from "effect"
   *
   * // ApplyFilters computes the final narrowed type:
   * type Result = Match.Types.ApplyFilters<
   *   string | number | boolean,
   *   Match.Types.Only<string>
   * >
   * // Result: string
   *
   * type ExclusionResult = Match.Types.ApplyFilters<
   *   string | number | boolean,
   *   Match.Types.Without<string>
   * >
   * // Result: number | boolean
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export type ApplyFilters<I, A> = A extends Only<infer X> ? X
    : A extends Without<infer X> ? Exclude<I, X>
    : never

  /**
   * Extracts tag values from a discriminated union based on a discriminant field.
   *
   * **Details**
   *
   * This utility type extracts the possible values of a discriminant field
   * from a union type. It's used internally to implement tag-based pattern
   * matching for discriminated unions.
   *
   * **Example** (Extracting discriminator tags)
   *
   * ```ts
   * import type { Match } from "effect"
   *
   * type Events =
   *   | { _tag: "click"; x: number; y: number }
   *   | { _tag: "keypress"; key: string }
   *   | { _tag: "scroll"; delta: number }
   *
   * type EventTags = Match.Types.Tags<"_tag", Events>
   * // Result: "click" | "keypress" | "scroll"
   *
   * type CustomTags = Match.Types.Tags<
   *   "type",
   *   | { type: "user"; name: string }
   *   | { type: "admin"; permissions: Array<string> }
   * >
   * // Result: "user" | "admin"
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export type Tags<D extends string, P> = P extends Record<D, infer X> ? X : never

  /**
   * Converts an array type to an intersection of its element types.
   *
   * **Details**
   *
   * This utility type takes an array of types and converts them into a single
   * intersection type. It's used internally when multiple patterns need to
   * be satisfied simultaneously (like in `Match.whenAnd`).
   *
   * **Example** (Converting arrays to intersections)
   *
   * ```ts
   * import type { Match } from "effect"
   *
   * type Combined = Match.Types.ArrayToIntersection<[
   *   { name: string },
   *   { age: number },
   *   { active: boolean }
   * ]>
   * // Result: { name: string } & { age: number } & { active: boolean }
   * //         = { name: string; age: number; active: boolean }
   *
   * // This type utility enables complex type intersections
   * // Complex type operations are handled by this utility type
   * // for advanced pattern matching scenarios
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export type ArrayToIntersection<A extends ReadonlyArray<any>> = T.UnionToIntersection<
    A[number]
  >

  /**
   * Extracts and narrows the matched type from an input type given a pattern.
   *
   * **Details**
   *
   * This is the core type utility that performs the actual type extraction
   * and narrowing logic. It handles the complex type-level computation that
   * determines what type results from applying a pattern to an input type.
   *
   * **Example** (Extracting matched types)
   *
   * ```ts
   * import { Match } from "effect"
   *
   * type StringExtract = Match.Types.ExtractMatch<
   *   string | number | boolean,
   *   typeof Match.string
   * >
   * // Result: string
   *
   * type ObjectExtract = Match.Types.ExtractMatch<
   *   { type: "user"; name: string } | { type: "admin"; role: string },
   *   { type: "user" }
   * >
   * // Result: { type: "user"; name: string }
   *
   * // This powers the type narrowing in:
   * Match.when(Match.string, (s) => s.toUpperCase())
   * //                      ^^^ s is correctly typed as string
   * ```
   *
   * @category types
   * @since 4.0.0
   */
  export type ExtractMatch<I, P> = [ExtractAndNarrow<I, P>] extends [infer EI] ? EI
    : never

  type Replace<A, B> = A extends Function ? A
    : A extends Record<string | number, any> ? { [K in keyof A]: K extends keyof B ? Replace<A[K], B[K]> : A[K] }
    : [B] extends [A] ? B
    : A

  type MaybeReplace<I, P> = [P] extends [I] ? P
    : [I] extends [P] ? Replace<I, P>
    : Fail

  type BuiltInObjects =
    | Function
    | Date
    | RegExp
    | Generator
    | { readonly [Symbol.toStringTag]: string }

  type IsPlainObject<T> = T extends BuiltInObjects ? false
    : T extends Record<string, any> ? true
    : false

  type Simplify<A> = { [K in keyof A]: A[K] } & {}

  type ExtractAndNarrow<Input, P> = P extends Predicate.Refinement<infer _In, infer _Out> ?
    _Out extends Input ? Extract<_Out, Input>
    : Extract<Input, _Out> :
    P extends SafeRefinement<infer _In, infer _R> ? [0] extends [1 & _R] ? Input
      : _In extends Input ? Extract<_In, Input>
      : Extract<Input, _In>
    : P extends Predicate.Predicate<infer _In> ? Extract<Input, _In>
    : Input extends infer I ? Exclude<
        I extends ReadonlyArray<any> ? P extends ReadonlyArray<any> ? {
              readonly [K in keyof I]: K extends keyof P ? ExtractAndNarrow<I[K], P[K]>
                : I[K]
            } extends infer R ? Fail extends R[keyof R] ? never
              : R
            : never
          : never
          : IsPlainObject<I> extends true ? string extends keyof I ? I extends P ? I
              : never
            : symbol extends keyof I ? I extends P ? I
              : never
            : Simplify<
              & { [RK in Extract<keyof I, keyof P>]-?: ExtractAndNarrow<I[RK], P[RK]> }
              & Omit<I, keyof P>
            > extends infer R ? keyof P extends NonFailKeys<R> ? R
              : never
            : never
          : MaybeReplace<I, P> extends infer R ? [I] extends [R] ? I
            : R
          : never,
        Fail
      > :
    never

  type NonFailKeys<A> = keyof A & {} extends infer K ? K extends keyof A ? A[K] extends Fail ? never : K
    : never :
    never
}
Referenced by 16 symbols