Hyperlinkv0.8.0-beta.28

Schema

Schema.toTaggedUnionfunctioneffect/Schema.ts:6120
toTaggedUnion<Tag, Members>

Augments an existing Union of tagged structs with utility methods keyed by the discriminant field.

Example (Adding tagged-union utilities to an existing union)

import { Schema } from "effect"

const A = Schema.TaggedStruct("A", { value: Schema.Number })
const B = Schema.TaggedStruct("B", { name: Schema.String })

const MyUnion = Schema.Union([A, B]).pipe(Schema.toTaggedUnion("_tag"))

// Pattern-match on the union
const result = MyUnion.match({ _tag: "A", value: 1 }, {
  A: (a) => `number: ${a.value}`,
  B: (b) => `name: ${b.name}`
})
combinatorsUnionTaggedUnion
Source effect/Schema.ts:612077 lines
export type toTaggedUnion<
  Tag extends PropertyKey,
  Members extends ReadonlyArray<Constraint & { readonly Type: { readonly [K in Tag]: PropertyKey } }>
> = Union<Members> & TaggedUnionUtils<Tag, Members>

/**
 * Augments an existing {@link Union} of tagged structs with utility methods keyed by the discriminant field.
 *
 * **Example** (Adding tagged-union utilities to an existing union)
 *
 * ```ts
 * import { Schema } from "effect"
 *
 * const A = Schema.TaggedStruct("A", { value: Schema.Number })
 * const B = Schema.TaggedStruct("B", { name: Schema.String })
 *
 * const MyUnion = Schema.Union([A, B]).pipe(Schema.toTaggedUnion("_tag"))
 *
 * // Pattern-match on the union
 * const result = MyUnion.match({ _tag: "A", value: 1 }, {
 *   A: (a) => `number: ${a.value}`,
 *   B: (b) => `name: ${b.name}`
 * })
 * ```
 *
 * @see {@link TaggedUnion} for a shorthand that builds the union from scratch
 * @category combinators
 * @since 4.0.0
 */
export function toTaggedUnion<const Tag extends PropertyKey>(tag: Tag) {
  return <const Members extends ReadonlyArray<Constraint & { readonly Type: { readonly [K in Tag]: PropertyKey } }>>(
    self: Union<Members>
  ): toTaggedUnion<Tag, Members> => {
    const cases: Record<PropertyKey, unknown> = {}
    const guards: Record<PropertyKey, (u: unknown) => boolean> = {}
    const isAnyOf = (keys: ReadonlyArray<PropertyKey>) => (value: Members[number]["Type"]) => keys.includes(value[tag])

    walk(self)

    return Object.assign(self, { cases, isAnyOf, guards, match }) as any

    function walk(schema: Constraint) {
      const ast = schema.ast

      if (
        SchemaAST.isUnion(ast) && "members" in schema && globalThis.Array.isArray(schema.members) &&
        schema.members.every(isSchema)
      ) {
        return schema.members.forEach(walk)
      }

      const sentinels = SchemaAST.collectSentinels(ast)
      if (sentinels.length > 0) {
        const literal = sentinels.find((s) => s.key === tag)?.literal
        if (Predicate.isPropertyKey(literal)) {
          cases[literal] = schema
          guards[literal] = is(toType(schema))
          return
        }
      }

      throw new globalThis.Error("No literal or unique symbol found")
    }

    function match() {
      if (arguments.length === 1) {
        const cases = arguments[0]
        return function(value: any) {
          return cases[value[tag]](value)
        }
      }
      const value = arguments[0]
      const cases = arguments[1]
      return cases[value[tag]](value)
    }
  }
}
Referenced by 1 symbols