/** * Immutable data constructors with discriminated-union support. * * The `Data` module provides base classes and factory functions for creating * immutable value types with a `_tag` field for discriminated unions. * It is the recommended way to define domain models, error types, and * lightweight ADTs in Effect applications. * * ## Mental model * * - **`Class`** — base class for plain immutable data. Extend it with a type * parameter to declare the fields. Instances are `Pipeable`. * - **`TaggedClass`** — like `Class` but automatically adds a `readonly _tag` * string literal field. Useful for single-variant types or ad-hoc tagged * values. * - **`TaggedEnum`** (type) + **`taggedEnum`** (value) — define a multi-variant * discriminated union from a simple record. `taggedEnum()` returns per-variant * constructors plus `$is` / `$match` helpers. * - **`Error`** — like `Class` but extends `Cause.YieldableError`, so instances * can be yielded inside `Effect.gen` to fail the effect. * - **`TaggedError`** — like `TaggedClass` but extends `Cause.YieldableError`. * Works with `Effect.catchTag` for tag-based error recovery. * * ## Common tasks * * - Define a simple value class → {@link Class} * - Define a value class with a `_tag` → {@link TaggedClass} * - Define a discriminated union with constructors → {@link TaggedEnum} + {@link taggedEnum} * - Define a yieldable error → {@link Error} * - Define a yieldable tagged error → {@link TaggedError} * - Type-guard a tagged value → `$is` from {@link taggedEnum} * - Pattern-match on a tagged union → `$match` from {@link taggedEnum} * * ## Gotchas * * - Variant records passed to `TaggedEnum` must **not** contain a `_tag` key; * the `_tag` is added automatically from the record key. * - When a class has no fields, the constructor argument is optional (`void`). * - `taggedEnum()` creates **plain objects**, not class instances. If you need * class-based variants, use `TaggedClass` or `TaggedError` instead. * - `TaggedEnum.WithGenerics` supports up to 4 generic type parameters. * * ## Quickstart * * **Example** (tagged union with pattern matching) * * ```ts * import { Data } from "effect" * * type Shape = Data.TaggedEnum<{ * Circle: { readonly radius: number } * Rect: { readonly width: number; readonly height: number } * }> * const { Circle, Rect, $match } = Data.taggedEnum() * * const area = $match({ * Circle: ({ radius }) => Math.PI * radius ** 2, * Rect: ({ width, height }) => width * height * }) * * console.log(area(Circle({ radius: 5 }))) * // 78.53981633974483 * console.log(area(Rect({ width: 3, height: 4 }))) * // 12 * ``` * * @see {@link Class} — plain immutable data class * @see {@link TaggedEnum} — discriminated union type * @see {@link taggedEnum} — discriminated union constructors * @see {@link TaggedError} — yieldable tagged error class * * @since 2.0.0 */ import type * as Cause from "./Cause.ts" import * as core from "./internal/core.ts" import * as Pipeable from "./Pipeable.ts" import * as Predicate from "./Predicate.ts" import type * as Types from "./Types.ts" import type { Unify } from "./Unify.ts" /** * Base class for immutable data types. * * Extend `Class` with a type parameter to declare fields. The constructor * accepts those fields as a single object argument. When there are no fields * the argument is optional. * * - Use when you need a lightweight immutable value type with `.pipe()` support. * - Instances are `Readonly` and `Pipeable`. * - If you also need a `_tag` discriminator, use {@link TaggedClass} instead. * - If you need a yieldable error, use {@link Error} or {@link TaggedError}. * * **Example** (defining a value class) * * ```ts * import { Data, Equal } from "effect" * * class Person extends Data.Class<{ readonly name: string }> {} * * const mike1 = new Person({ name: "Mike" }) * const mike2 = new Person({ name: "Mike" }) * * console.log(Equal.equals(mike1, mike2)) * // true * ``` * * @see {@link TaggedClass} — adds a `_tag` field * @see {@link Error} — yieldable error variant * * @category constructors * @since 2.0.0 */ export const Class: new = {}>( args: Types.VoidIfEmpty<{ readonly [P in keyof A]: A[P] }> ) => Readonly & Pipeable.Pipeable = class extends Pipeable.Class { constructor(props: any) { super() if (props) { Object.assign(this, props) } } } as any /** * Base class for immutable data types with a `_tag` discriminator. * * Like {@link Class}, but the resulting instances also carry a * `readonly _tag: Tag` property. The `_tag` is excluded from the constructor * argument. * * - Use when you need a single-variant tagged type or an ad-hoc discriminator. * - For multi-variant unions, prefer {@link TaggedEnum} + {@link taggedEnum}. * - For yieldable errors, use {@link TaggedError}. * * **Example** (defining a tagged class) * * ```ts * import { Data } from "effect" * * class Person extends Data.TaggedClass("Person")<{ * readonly name: string * }> {} * * const mike = new Person({ name: "Mike" }) * console.log(mike._tag) * // "Person" * ``` * * @see {@link Class} — without a `_tag` * @see {@link TaggedError} — tagged error variant * @see {@link TaggedEnum} — multi-variant unions * * @category constructors * @since 2.0.0 */ export const TaggedClass = ( tag: Tag ): new = {}>( args: Types.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }> ) => Readonly & { readonly _tag: Tag } & Pipeable.Pipeable => class extends Class { readonly _tag = tag } as any /** * Transforms a record of variant definitions into a discriminated union type. * * Each key in the record becomes a variant with `readonly _tag` set to that * key. Use with {@link taggedEnum} to get runtime constructors, type guards, * and pattern matching. * * - Use when you have two or more variants that share a common `_tag` * discriminator. * - Variant records must **not** include a `_tag` property — it is added * automatically. * - For generic tagged enums, see {@link TaggedEnum.WithGenerics}. * * **Example** (defining a tagged enum) * * ```ts * import { Data } from "effect" * * type HttpError = Data.TaggedEnum<{ * BadRequest: { readonly status: 400; readonly message: string } * NotFound: { readonly status: 404 } * }> * * // Equivalent to: * // | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } * // | { readonly _tag: "NotFound"; readonly status: 404 } * * const { BadRequest, NotFound } = Data.taggedEnum() * * const err = BadRequest({ status: 400, message: "missing id" }) * console.log(err._tag) * // "BadRequest" * ``` * * @see {@link taggedEnum} — runtime constructors for a `TaggedEnum` * @see {@link TaggedEnum.WithGenerics} — generic tagged enums * @see {@link TaggedEnum.Constructor} — the constructor object type * * @category models * @since 2.0.0 */ export type TaggedEnum< A extends Record> & UntaggedChildren > = keyof A extends infer Tag ? Tag extends keyof A ? Types.Simplify< { readonly _tag: Tag } & { readonly [K in keyof A[Tag]]: A[Tag][K] } > : never : never type ChildrenAreTagged = keyof A extends infer K ? K extends keyof A ? "_tag" extends keyof A[K] ? true : false : never : never type UntaggedChildren = true extends ChildrenAreTagged ? "It looks like you're trying to create a tagged enum, but one or more of its members already has a `_tag` property." : unknown /** * Namespace for `TaggedEnum` utility types. * * Provides helper types for: * - Generic tagged enums ({@link TaggedEnum.WithGenerics}, {@link TaggedEnum.Kind}) * - Extracting constructor arguments ({@link TaggedEnum.Args}) and variant * values ({@link TaggedEnum.Value}) * - Full constructor objects ({@link TaggedEnum.Constructor}) * * @category types * @since 2.0.0 */ export declare namespace TaggedEnum { /** * Defines a tagged enum shape that accepts generic type parameters. * * Extend this interface and set `taggedEnum` to your union type, using * `this["A"]`, `this["B"]`, etc. as placeholders for the generics. The * `Count` parameter declares how many generics are used (up to 4). * * - Use when variant payloads need to be parameterized (e.g., `Result`). * - Pass the interface (not the type alias) to {@link taggedEnum} to get * generic-aware constructors. * * **Example** (generic tagged enum) * * ```ts * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * * interface MyResultDef extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * * const { Failure, Success } = Data.taggedEnum() * * const ok = Success({ value: 42 }) * // ok: { readonly _tag: "Success"; readonly value: number } * ``` * * @see {@link Kind} — apply concrete types to a `WithGenerics` definition * @see {@link taggedEnum} — runtime constructors * * @since 2.0.0 */ export interface WithGenerics { readonly taggedEnum: { readonly _tag: string } readonly numberOfGenerics: Count readonly A: unknown readonly B: unknown readonly C: unknown readonly D: unknown } /** * Applies concrete type arguments to a `WithGenerics` definition, producing * the resulting tagged union type. * * - Use to refer to a specific instantiation of a generic tagged enum in * type signatures. * * **Example** (applying generics) * * ```ts * import type { Data } from "effect" * * type Option = Data.TaggedEnum<{ * None: {} * Some: { readonly value: A } * }> * interface OptionDef extends Data.TaggedEnum.WithGenerics<1> { * readonly taggedEnum: Option * } * * // Resolve to the concrete union for `string` * type StringOption = Data.TaggedEnum.Kind * // { _tag: "None" } | { _tag: "Some"; value: string } * ``` * * @see {@link WithGenerics} — define the generic shape * * @since 2.0.0 */ export type Kind< Z extends WithGenerics, A = unknown, B = unknown, C = unknown, D = unknown > = (Z & { readonly A: A readonly B: B readonly C: C readonly D: D })["taggedEnum"] /** * Extracts the constructor argument type for a specific variant of a tagged * union. * * Returns `void` if the variant has no fields beyond `_tag`. * * **Example** (extracting variant args) * * ```ts * import type { Data } from "effect" * * type Result = * | { readonly _tag: "Ok"; readonly value: number } * | { readonly _tag: "Err"; readonly error: string } * * type OkArgs = Data.TaggedEnum.Args * // { readonly value: number } * * type ErrArgs = Data.TaggedEnum.Args * // { readonly error: string } * ``` * * @see {@link Value} — extracts the full variant type (including `_tag`) * * @since 2.0.0 */ export type Args< A extends { readonly _tag: string }, K extends A["_tag"], E = Extract > = { readonly [K in keyof E as K extends "_tag" ? never : K]: E[K] } extends infer T ? Types.VoidIfEmpty : never /** * Extracts the full variant type (including `_tag`) for a specific tag. * * **Example** (extracting a variant type) * * ```ts * import type { Data } from "effect" * * type Result = * | { readonly _tag: "Ok"; readonly value: number } * | { readonly _tag: "Err"; readonly error: string } * * type OkVariant = Data.TaggedEnum.Value * // { readonly _tag: "Ok"; readonly value: number } * ``` * * @see {@link Args} — extracts fields without `_tag` * * @since 2.0.0 */ export type Value< A extends { readonly _tag: string }, K extends A["_tag"] > = Extract /** * The full constructor-object type returned by {@link taggedEnum}. * * Includes: * - A constructor function for each variant (keyed by tag name) * - `$is(tag)` — returns a type-guard for the given variant * - `$match` — exhaustive pattern matching (data-last or data-first) * * **Example** (using the constructor object) * * ```ts * import { Data } from "effect" * * type Shape = * | { readonly _tag: "Circle"; readonly radius: number } * | { readonly _tag: "Rect"; readonly w: number; readonly h: number } * * const { Circle, Rect, $is, $match } = Data.taggedEnum() * * const shape = Circle({ radius: 10 }) * * // Type guard * if ($is("Circle")(shape)) { * console.log(shape.radius) * } * * // Pattern matching * const label = $match(shape, { * Circle: (s) => `circle r=${s.radius}`, * Rect: (s) => `rect ${s.w}x${s.h}` * }) * ``` * * @see {@link taggedEnum} — creates a `Constructor` * * @since 3.1.0 * @category types */ export type Constructor = Types.Simplify< { readonly [Tag in A["_tag"]]: ConstructorFrom< Extract, "_tag" > } & { readonly $is: ( tag: Tag ) => (u: unknown) => u is Extract readonly $match: { < Cases extends { readonly [Tag in A["_tag"]]: ( args: Extract ) => any } >( cases: Cases ): (value: A) => Unify> < Cases extends { readonly [Tag in A["_tag"]]: ( args: Extract ) => any } >( value: A, cases: Cases ): Unify> } } > /** * Function type that constructs a tagged-union variant from its fields, * excluding the keys listed in `Tag`. * * Returns `void` when no fields remain after excluding `Tag` keys. * * @since 4.0.0 */ export type ConstructorFrom = ( args: Types.VoidIfEmpty<{ readonly [P in keyof A as P extends Tag ? never : P]: A[P] }> ) => A /** * Type-guard and pattern-matching interface for generic tagged enums. * * This is the `$is` / `$match` portion of the object returned by * {@link taggedEnum} when used with a {@link WithGenerics} definition. * * @see {@link Constructor} — the non-generic equivalent * * @since 3.2.0 */ export interface GenericMatchers> { readonly $is: ( tag: Tag ) => { >( u: T ): u is T & { readonly _tag: Tag } (u: unknown): u is Extract, { readonly _tag: Tag }> } readonly $match: { < A, B, C, D, Cases extends { readonly [Tag in Z["taggedEnum"]["_tag"]]: ( args: Extract< TaggedEnum.Kind, { readonly _tag: Tag } > ) => any } >( cases: Cases ): ( self: TaggedEnum.Kind ) => Unify> < A, B, C, D, Cases extends { readonly [Tag in Z["taggedEnum"]["_tag"]]: ( args: Extract< TaggedEnum.Kind, { readonly _tag: Tag } > ) => any } >( self: TaggedEnum.Kind, cases: Cases ): Unify> } } } /** * Creates runtime constructors, type guards, and pattern matching for a * {@link TaggedEnum} type. * * Returns an object with: * - One constructor per variant (keyed by tag name) * - `$is(tag)` — returns a type-guard function * - `$match` — exhaustive pattern matching (data-first or data-last) * * - Use when you have a `TaggedEnum` type and need to construct/inspect values. * - Constructors produce **plain objects** (not class instances). * - For generic enums, pass a {@link TaggedEnum.WithGenerics} interface. * * **Example** (basic usage) * * ```ts * import { Data } from "effect" * * type HttpError = Data.TaggedEnum<{ * BadRequest: { readonly message: string } * NotFound: { readonly url: string } * }> * * const { BadRequest, NotFound, $is, $match } = Data.taggedEnum() * * const err = NotFound({ url: "/missing" }) * * // Type guard * console.log($is("NotFound")(err)) // true * * // Pattern matching * const msg = $match(err, { * BadRequest: (e) => e.message, * NotFound: (e) => `${e.url} not found` * }) * console.log(msg) // "/missing not found" * ``` * * **Example** (generic tagged enum) * * ```ts * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * interface MyResultDef extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * const { Failure, Success } = Data.taggedEnum() * * const ok = Success({ value: 42 }) * // ok: { readonly _tag: "Success"; readonly value: number } * ``` * * @see {@link TaggedEnum} — the type-level companion * @see {@link TaggedEnum.Constructor} — the returned object type * @see {@link TaggedEnum.WithGenerics} — generic enum support * * @category constructors * @since 2.0.0 */ export const taggedEnum: { /** * Creates runtime constructors, type guards, and pattern matching for a * {@link TaggedEnum} type. * * Returns an object with: * - One constructor per variant (keyed by tag name) * - `$is(tag)` — returns a type-guard function * - `$match` — exhaustive pattern matching (data-first or data-last) * * - Use when you have a `TaggedEnum` type and need to construct/inspect values. * - Constructors produce **plain objects** (not class instances). * - For generic enums, pass a {@link TaggedEnum.WithGenerics} interface. * * **Example** (basic usage) * * ```ts * import { Data } from "effect" * * type HttpError = Data.TaggedEnum<{ * BadRequest: { readonly message: string } * NotFound: { readonly url: string } * }> * * const { BadRequest, NotFound, $is, $match } = Data.taggedEnum() * * const err = NotFound({ url: "/missing" }) * * // Type guard * console.log($is("NotFound")(err)) // true * * // Pattern matching * const msg = $match(err, { * BadRequest: (e) => e.message, * NotFound: (e) => `${e.url} not found` * }) * console.log(msg) // "/missing not found" * ``` * * **Example** (generic tagged enum) * * ```ts * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * interface MyResultDef extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * const { Failure, Success } = Data.taggedEnum() * * const ok = Success({ value: 42 }) * // ok: { readonly _tag: "Success"; readonly value: number } * ``` * * @see {@link TaggedEnum} — the type-level companion * @see {@link TaggedEnum.Constructor} — the returned object type * @see {@link TaggedEnum.WithGenerics} — generic enum support * * @category constructors * @since 2.0.0 */ >(): Types.Simplify< { readonly [Tag in Z["taggedEnum"]["_tag"]]: ( args: TaggedEnum.Args< TaggedEnum.Kind, Tag, Extract, { readonly _tag: Tag }> > ) => TaggedEnum.Value, Tag> } & TaggedEnum.GenericMatchers > /** * Creates runtime constructors, type guards, and pattern matching for a * {@link TaggedEnum} type. * * Returns an object with: * - One constructor per variant (keyed by tag name) * - `$is(tag)` — returns a type-guard function * - `$match` — exhaustive pattern matching (data-first or data-last) * * - Use when you have a `TaggedEnum` type and need to construct/inspect values. * - Constructors produce **plain objects** (not class instances). * - For generic enums, pass a {@link TaggedEnum.WithGenerics} interface. * * **Example** (basic usage) * * ```ts * import { Data } from "effect" * * type HttpError = Data.TaggedEnum<{ * BadRequest: { readonly message: string } * NotFound: { readonly url: string } * }> * * const { BadRequest, NotFound, $is, $match } = Data.taggedEnum() * * const err = NotFound({ url: "/missing" }) * * // Type guard * console.log($is("NotFound")(err)) // true * * // Pattern matching * const msg = $match(err, { * BadRequest: (e) => e.message, * NotFound: (e) => `${e.url} not found` * }) * console.log(msg) // "/missing not found" * ``` * * **Example** (generic tagged enum) * * ```ts * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * interface MyResultDef extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * const { Failure, Success } = Data.taggedEnum() * * const ok = Success({ value: 42 }) * // ok: { readonly _tag: "Success"; readonly value: number } * ``` * * @see {@link TaggedEnum} — the type-level companion * @see {@link TaggedEnum.Constructor} — the returned object type * @see {@link TaggedEnum.WithGenerics} — generic enum support * * @category constructors * @since 2.0.0 */ >(): Types.Simplify< { readonly [Tag in Z["taggedEnum"]["_tag"]]: ( args: TaggedEnum.Args< TaggedEnum.Kind, Tag, Extract, { readonly _tag: Tag }> > ) => TaggedEnum.Value, Tag> } & TaggedEnum.GenericMatchers > /** * Creates runtime constructors, type guards, and pattern matching for a * {@link TaggedEnum} type. * * Returns an object with: * - One constructor per variant (keyed by tag name) * - `$is(tag)` — returns a type-guard function * - `$match` — exhaustive pattern matching (data-first or data-last) * * - Use when you have a `TaggedEnum` type and need to construct/inspect values. * - Constructors produce **plain objects** (not class instances). * - For generic enums, pass a {@link TaggedEnum.WithGenerics} interface. * * **Example** (basic usage) * * ```ts * import { Data } from "effect" * * type HttpError = Data.TaggedEnum<{ * BadRequest: { readonly message: string } * NotFound: { readonly url: string } * }> * * const { BadRequest, NotFound, $is, $match } = Data.taggedEnum() * * const err = NotFound({ url: "/missing" }) * * // Type guard * console.log($is("NotFound")(err)) // true * * // Pattern matching * const msg = $match(err, { * BadRequest: (e) => e.message, * NotFound: (e) => `${e.url} not found` * }) * console.log(msg) // "/missing not found" * ``` * * **Example** (generic tagged enum) * * ```ts * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * interface MyResultDef extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * const { Failure, Success } = Data.taggedEnum() * * const ok = Success({ value: 42 }) * // ok: { readonly _tag: "Success"; readonly value: number } * ``` * * @see {@link TaggedEnum} — the type-level companion * @see {@link TaggedEnum.Constructor} — the returned object type * @see {@link TaggedEnum.WithGenerics} — generic enum support * * @category constructors * @since 2.0.0 */ >(): Types.Simplify< { readonly [Tag in Z["taggedEnum"]["_tag"]]: ( args: TaggedEnum.Args< TaggedEnum.Kind, Tag, Extract, { readonly _tag: Tag }> > ) => TaggedEnum.Value, Tag> } & TaggedEnum.GenericMatchers > /** * Creates runtime constructors, type guards, and pattern matching for a * {@link TaggedEnum} type. * * Returns an object with: * - One constructor per variant (keyed by tag name) * - `$is(tag)` — returns a type-guard function * - `$match` — exhaustive pattern matching (data-first or data-last) * * - Use when you have a `TaggedEnum` type and need to construct/inspect values. * - Constructors produce **plain objects** (not class instances). * - For generic enums, pass a {@link TaggedEnum.WithGenerics} interface. * * **Example** (basic usage) * * ```ts * import { Data } from "effect" * * type HttpError = Data.TaggedEnum<{ * BadRequest: { readonly message: string } * NotFound: { readonly url: string } * }> * * const { BadRequest, NotFound, $is, $match } = Data.taggedEnum() * * const err = NotFound({ url: "/missing" }) * * // Type guard * console.log($is("NotFound")(err)) // true * * // Pattern matching * const msg = $match(err, { * BadRequest: (e) => e.message, * NotFound: (e) => `${e.url} not found` * }) * console.log(msg) // "/missing not found" * ``` * * **Example** (generic tagged enum) * * ```ts * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * interface MyResultDef extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * const { Failure, Success } = Data.taggedEnum() * * const ok = Success({ value: 42 }) * // ok: { readonly _tag: "Success"; readonly value: number } * ``` * * @see {@link TaggedEnum} — the type-level companion * @see {@link TaggedEnum.Constructor} — the returned object type * @see {@link TaggedEnum.WithGenerics} — generic enum support * * @category constructors * @since 2.0.0 */ >(): Types.Simplify< { readonly [Tag in Z["taggedEnum"]["_tag"]]: ( args: TaggedEnum.Args< TaggedEnum.Kind, Tag, Extract, { readonly _tag: Tag }> > ) => TaggedEnum.Value, Tag> } & TaggedEnum.GenericMatchers > /** * Creates runtime constructors, type guards, and pattern matching for a * {@link TaggedEnum} type. * * Returns an object with: * - One constructor per variant (keyed by tag name) * - `$is(tag)` — returns a type-guard function * - `$match` — exhaustive pattern matching (data-first or data-last) * * - Use when you have a `TaggedEnum` type and need to construct/inspect values. * - Constructors produce **plain objects** (not class instances). * - For generic enums, pass a {@link TaggedEnum.WithGenerics} interface. * * **Example** (basic usage) * * ```ts * import { Data } from "effect" * * type HttpError = Data.TaggedEnum<{ * BadRequest: { readonly message: string } * NotFound: { readonly url: string } * }> * * const { BadRequest, NotFound, $is, $match } = Data.taggedEnum() * * const err = NotFound({ url: "/missing" }) * * // Type guard * console.log($is("NotFound")(err)) // true * * // Pattern matching * const msg = $match(err, { * BadRequest: (e) => e.message, * NotFound: (e) => `${e.url} not found` * }) * console.log(msg) // "/missing not found" * ``` * * **Example** (generic tagged enum) * * ```ts * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * interface MyResultDef extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * const { Failure, Success } = Data.taggedEnum() * * const ok = Success({ value: 42 }) * // ok: { readonly _tag: "Success"; readonly value: number } * ``` * * @see {@link TaggedEnum} — the type-level companion * @see {@link TaggedEnum.Constructor} — the returned object type * @see {@link TaggedEnum.WithGenerics} — generic enum support * * @category constructors * @since 2.0.0 */ (): TaggedEnum.Constructor } = () => new Proxy( {}, { get(_target, tag, _receiver) { if (tag === "$is") { return Predicate.isTagged } else if (tag === "$match") { return taggedMatch } return (props: any) => ({ ...props, _tag: tag }) } } ) as any function taggedMatch< A extends { readonly _tag: string }, Cases extends { readonly [K in A["_tag"]]: (args: Extract) => any } >(self: A, cases: Cases): ReturnType function taggedMatch< A extends { readonly _tag: string }, Cases extends { readonly [K in A["_tag"]]: (args: Extract) => any } >(cases: Cases): (value: A) => ReturnType function taggedMatch< A extends { readonly _tag: string }, Cases extends { readonly [K in A["_tag"]]: (args: Extract) => any } >(): any { if (arguments.length === 1) { const cases = arguments[0] as Cases return function(value: A): ReturnType { return cases[value._tag as A["_tag"]](value as any) } } const value = arguments[0] as A const cases = arguments[1] as Cases return cases[value._tag as A["_tag"]](value as any) } /** * Base class for yieldable errors. * * Extends `Cause.YieldableError`, so instances can be yielded inside * `Effect.gen` to fail the enclosing effect. Fields are passed as a single * object; when there are no fields the argument is optional. * * - Use for errors that do **not** need tag-based discrimination. * - If you need `Effect.catchTag` support, use {@link TaggedError} instead. * - If a `message` field is provided, it becomes the error's `.message`. * * **Example** (defining a yieldable error) * * ```ts * import { Data, Effect } from "effect" * * class NetworkError extends Data.Error<{ * readonly code: number * readonly message: string * }> {} * * const program = Effect.gen(function*() { * return yield* new NetworkError({ code: 500, message: "timeout" }) * }) * * // The effect fails with a NetworkError * Effect.runSync(Effect.exit(program)) * ``` * * @see {@link TaggedError} — adds a `_tag` for `Effect.catchTag` * @see {@link Class} — non-error data class * * @category constructors * @since 2.0.0 */ export const Error: new = {}>( args: Types.VoidIfEmpty<{ readonly [P in keyof A]: A[P] }> ) => Cause.YieldableError & Readonly = core.Error /** * Creates a tagged error class with a `_tag` discriminator. * * Like {@link Error}, but instances also carry a `readonly _tag` property, * enabling `Effect.catchTag` and `Effect.catchTags` for tag-based recovery. * The `_tag` is excluded from the constructor argument. * * - Use for domain errors in Effect applications where you want * discriminated-union error handling. * - Yielding an instance inside `Effect.gen` fails the effect with this error. * * **Example** (tag-based error recovery) * * ```ts * import { Data, Effect } from "effect" * * class NotFound extends Data.TaggedError("NotFound")<{ * readonly resource: string * }> {} * * class Forbidden extends Data.TaggedError("Forbidden")<{ * readonly reason: string * }> {} * * const program = Effect.gen(function*() { * return yield* new NotFound({ resource: "/users/42" }) * }) * * const recovered = program.pipe( * Effect.catchTag("NotFound", (e) => * Effect.succeed(`missing: ${e.resource}`)) * ) * ``` * * @see {@link Error} — without a `_tag` * @see {@link TaggedClass} — tagged class that is not an error * * @category constructors * @since 2.0.0 */ export const TaggedError: ( tag: Tag ) => new = {}>( args: Types.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }> ) => Cause.YieldableError & { readonly _tag: Tag } & Readonly = core.TaggedError as any