/** * @since 2.0.0 */ import type * as Cause from "./Cause.js" import * as core from "./internal/core.js" import * as internal from "./internal/data.js" import { StructuralPrototype } from "./internal/effectable.js" import * as Predicate from "./Predicate.js" import type * as Types from "./Types.js" import type { Unify } from "./Unify.js" /** * @since 2.0.0 */ export declare namespace Case { /** * @since 2.0.0 * @category models */ export interface Constructor { ( args: Types.Equals, {}> extends true ? void : { readonly [P in keyof A as P extends Tag ? never : P]: A[P] } ): A } } /** * @example * ```ts * import * as assert from "node:assert" * import { Data, Equal } from "effect" * * const alice = Data.struct({ name: "Alice", age: 30 }) * * const bob = Data.struct({ name: "Bob", age: 40 }) * * assert.deepStrictEqual(Equal.equals(alice, alice), true) * assert.deepStrictEqual(Equal.equals(alice, Data.struct({ name: "Alice", age: 30 })), true) * * assert.deepStrictEqual(Equal.equals(alice, { name: "Alice", age: 30 }), false) * assert.deepStrictEqual(Equal.equals(alice, bob), false) * ``` * * @category constructors * @since 2.0.0 */ export const struct: >(a: A) => { readonly [P in keyof A]: A[P] } = internal.struct /** * @category constructors * @since 2.0.0 */ export const unsafeStruct = >(as: A): { readonly [P in keyof A]: A[P] } => Object.setPrototypeOf(as, StructuralPrototype) /** * @example * ```ts * import * as assert from "node:assert" * import { Data, Equal } from "effect" * * const alice = Data.tuple("Alice", 30) * * const bob = Data.tuple("Bob", 40) * * assert.deepStrictEqual(Equal.equals(alice, alice), true) * assert.deepStrictEqual(Equal.equals(alice, Data.tuple("Alice", 30)), true) * * assert.deepStrictEqual(Equal.equals(alice, ["Alice", 30]), false) * assert.deepStrictEqual(Equal.equals(alice, bob), false) * ``` * * @category constructors * @since 2.0.0 */ export const tuple = >(...as: As): Readonly => unsafeArray(as) /** * @example * ```ts * import * as assert from "node:assert" * import { Data, Equal } from "effect" * * const alice = Data.struct({ name: "Alice", age: 30 }) * const bob = Data.struct({ name: "Bob", age: 40 }) * * const persons = Data.array([alice, bob]) * * assert.deepStrictEqual( * Equal.equals( * persons, * Data.array([ * Data.struct({ name: "Alice", age: 30 }), * Data.struct({ name: "Bob", age: 40 }) * ]) * ), * true * ) * ``` * * @category constructors * @since 2.0.0 */ export const array = >(as: As): Readonly => unsafeArray(as.slice(0) as unknown as As) /** * @category constructors * @since 2.0.0 */ export const unsafeArray = >(as: As): Readonly => Object.setPrototypeOf(as, internal.ArrayProto) const _case = (): Case.Constructor => (args) => (args === undefined ? Object.create(StructuralPrototype) : struct(args)) as any export { /** * Provides a constructor for the specified `Case`. * * @example * ```ts * import * as assert from "node:assert" * import { Data, Equal } from "effect" * * interface Person { * readonly name: string * } * * // Creating a constructor for the specified Case * const Person = Data.case() * * // Creating instances of Person * const mike1 = Person({ name: "Mike" }) * const mike2 = Person({ name: "Mike" }) * const john = Person({ name: "John" }) * * // Checking equality * assert.deepStrictEqual(Equal.equals(mike1, mike2), true) * assert.deepStrictEqual(Equal.equals(mike1, john), false) * * ``` * @since 2.0.0 * @category constructors */ _case as case } /** * Provides a tagged constructor for the specified `Case`. * * @example * ```ts * import * as assert from "node:assert" * import { Data } from "effect" * * interface Person { * readonly _tag: "Person" // the tag * readonly name: string * } * * const Person = Data.tagged("Person") * * const mike = Person({ name: "Mike" }) * * assert.deepEqual(mike, { _tag: "Person", name: "Mike" }) * ``` * * @since 2.0.0 * @category constructors */ export const tagged = ( tag: A["_tag"] ): Case.Constructor => (args) => { const value = args === undefined ? Object.create(StructuralPrototype) : struct(args) value._tag = tag return value } /** * Provides a constructor for a Case Class. * * @example * ```ts * import * as assert from "node:assert" * import { Data, Equal } from "effect" * * class Person extends Data.Class<{ readonly name: string }> {} * * // Creating instances of Person * const mike1 = new Person({ name: "Mike" }) * const mike2 = new Person({ name: "Mike" }) * const john = new Person({ name: "John" }) * * // Checking equality * assert.deepStrictEqual(Equal.equals(mike1, mike2), true) * assert.deepStrictEqual(Equal.equals(mike1, john), false) * ``` * * @since 2.0.0 * @category constructors */ export const Class: new = {}>( args: Types.Equals extends true ? void : { readonly [P in keyof A]: A[P] } ) => Readonly = internal.Structural as any /** * Provides a Tagged constructor for a Case Class. * * @example * ```ts * import * as assert from "node:assert" * import { Data, Equal } from "effect" * * class Person extends Data.TaggedClass("Person")<{ readonly name: string }> {} * * // Creating instances of Person * const mike1 = new Person({ name: "Mike" }) * const mike2 = new Person({ name: "Mike" }) * const john = new Person({ name: "John" }) * * // Checking equality * assert.deepStrictEqual(Equal.equals(mike1, mike2), true) * assert.deepStrictEqual(Equal.equals(mike1, john), false) * * assert.deepStrictEqual(mike1._tag, "Person") * ``` * * @since 2.0.0 * @category constructors */ export const TaggedClass = ( tag: Tag ): new = {}>( args: Types.Equals extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] } ) => Readonly & { readonly _tag: Tag } => { class Base extends Class { readonly _tag = tag } return Base as any } /** * @since 2.0.0 * @category constructors */ export const Structural: new( args: Types.Equals extends true ? void : { readonly [P in keyof A]: A[P] } ) => {} = internal.Structural as any /** * Create a tagged enum data type, which is a union of `Data` structs. * * ```ts * import * as assert from "node:assert" * import { Data } from "effect" * * type HttpError = Data.TaggedEnum<{ * BadRequest: { readonly status: 400, readonly message: string } * NotFound: { readonly status: 404, readonly message: string } * }> * * // Equivalent to: * type HttpErrorPlain = * | { * readonly _tag: "BadRequest" * readonly status: 400 * readonly message: string * } * | { * readonly _tag: "NotFound" * readonly status: 404 * readonly message: string * } * ``` * * @since 2.0.0 * @category models */ 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 /** * @since 2.0.0 */ export declare namespace TaggedEnum { /** * @since 2.0.0 * @category models */ export interface WithGenerics { readonly taggedEnum: { readonly _tag: string } readonly numberOfGenerics: Count readonly A: unknown readonly B: unknown readonly C: unknown readonly D: unknown } /** * @since 2.0.0 * @category models */ 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"] /** * @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 ? {} extends T ? void : T : never /** * @since 2.0.0 */ export type Value< A extends { readonly _tag: string }, K extends A["_tag"] > = Extract /** * @since 3.1.0 */ export type Constructor = Types.Simplify< & { readonly [Tag in A["_tag"]]: Case.Constructor, "_tag"> } & { readonly $is: (tag: Tag) => (u: unknown) => u is Extract readonly $match: { < const Cases extends { readonly [Tag in A["_tag"]]: (args: Extract) => any } >( cases: Cases & { [K in Exclude]: never } ): (value: A) => Unify> < const Cases extends { readonly [Tag in A["_tag"]]: (args: Extract) => any } >( value: A, cases: Cases & { [K in Exclude]: never } ): Unify> } } > /** * @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, { readonly _tag: Tag }> ) => any } >( cases: Cases & { [K in Exclude]: never } ): (self: TaggedEnum.Kind) => Unify> < A, B, C, D, Cases extends { readonly [Tag in Z["taggedEnum"]["_tag"]]: ( args: Extract, { readonly _tag: Tag }> ) => any } >( self: TaggedEnum.Kind, cases: Cases & { [K in Exclude]: never } ): Unify> } } } /** * Create a constructor for a tagged union of `Data` structs. * * You can also pass a `TaggedEnum.WithGenerics` if you want to add generics to * the constructor. * * @example * ```ts * import { Data } from "effect" * * const { BadRequest, NotFound } = Data.taggedEnum< * | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } * | { readonly _tag: "NotFound"; readonly status: 404; readonly message: string } * >() * * const notFound = NotFound({ status: 404, message: "Not Found" }) * ``` * * @example * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * interface MyResultDefinition extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * const { Failure, Success } = Data.taggedEnum() * * const success = Success({ value: 1 }) * * @category constructors * @since 2.0.0 */ export const taggedEnum: { /** * Create a constructor for a tagged union of `Data` structs. * * You can also pass a `TaggedEnum.WithGenerics` if you want to add generics to * the constructor. * * @example * ```ts * import { Data } from "effect" * * const { BadRequest, NotFound } = Data.taggedEnum< * | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } * | { readonly _tag: "NotFound"; readonly status: 404; readonly message: string } * >() * * const notFound = NotFound({ status: 404, message: "Not Found" }) * ``` * * @example * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * interface MyResultDefinition extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * const { Failure, Success } = Data.taggedEnum() * * const success = Success({ value: 1 }) * * @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 > /** * Create a constructor for a tagged union of `Data` structs. * * You can also pass a `TaggedEnum.WithGenerics` if you want to add generics to * the constructor. * * @example * ```ts * import { Data } from "effect" * * const { BadRequest, NotFound } = Data.taggedEnum< * | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } * | { readonly _tag: "NotFound"; readonly status: 404; readonly message: string } * >() * * const notFound = NotFound({ status: 404, message: "Not Found" }) * ``` * * @example * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * interface MyResultDefinition extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * const { Failure, Success } = Data.taggedEnum() * * const success = Success({ value: 1 }) * * @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 > /** * Create a constructor for a tagged union of `Data` structs. * * You can also pass a `TaggedEnum.WithGenerics` if you want to add generics to * the constructor. * * @example * ```ts * import { Data } from "effect" * * const { BadRequest, NotFound } = Data.taggedEnum< * | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } * | { readonly _tag: "NotFound"; readonly status: 404; readonly message: string } * >() * * const notFound = NotFound({ status: 404, message: "Not Found" }) * ``` * * @example * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * interface MyResultDefinition extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * const { Failure, Success } = Data.taggedEnum() * * const success = Success({ value: 1 }) * * @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 > /** * Create a constructor for a tagged union of `Data` structs. * * You can also pass a `TaggedEnum.WithGenerics` if you want to add generics to * the constructor. * * @example * ```ts * import { Data } from "effect" * * const { BadRequest, NotFound } = Data.taggedEnum< * | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } * | { readonly _tag: "NotFound"; readonly status: 404; readonly message: string } * >() * * const notFound = NotFound({ status: 404, message: "Not Found" }) * ``` * * @example * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * interface MyResultDefinition extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * const { Failure, Success } = Data.taggedEnum() * * const success = Success({ value: 1 }) * * @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 > /** * Create a constructor for a tagged union of `Data` structs. * * You can also pass a `TaggedEnum.WithGenerics` if you want to add generics to * the constructor. * * @example * ```ts * import { Data } from "effect" * * const { BadRequest, NotFound } = Data.taggedEnum< * | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } * | { readonly _tag: "NotFound"; readonly status: 404; readonly message: string } * >() * * const notFound = NotFound({ status: 404, message: "Not Found" }) * ``` * * @example * import { Data } from "effect" * * type MyResult = Data.TaggedEnum<{ * Failure: { readonly error: E } * Success: { readonly value: A } * }> * interface MyResultDefinition extends Data.TaggedEnum.WithGenerics<2> { * readonly taggedEnum: MyResult * } * const { Failure, Success } = Data.taggedEnum() * * const success = Success({ value: 1 }) * * @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 tagged(tag as string) } }) 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) } /** * Provides a constructor for a Case Class. * * @since 2.0.0 * @category constructors */ export const Error: new = {}>( args: Types.Equals extends true ? void : { readonly [P in keyof A]: A[P] } ) => Cause.YieldableError & Readonly = (function() { const plainArgsSymbol = Symbol.for("effect/Data/Error/plainArgs") const O = { BaseEffectError: class extends core.YieldableError { constructor(args: any) { super(args?.message, args?.cause ? { cause: args.cause } : undefined) if (args) { Object.assign(this, args) // @effect-diagnostics-next-line floatingEffect:off Object.defineProperty(this, plainArgsSymbol, { value: args, enumerable: false }) } } toJSON() { return { ...(this as any)[plainArgsSymbol], ...this } } } as any } return O.BaseEffectError })() /** * @since 2.0.0 * @category constructors */ export const TaggedError = (tag: Tag): new = {}>( args: Types.Equals extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] } ) => Cause.YieldableError & { readonly _tag: Tag } & Readonly => { const O = { BaseEffectError: class extends Error<{}> { readonly _tag = tag } } ;(O.BaseEffectError.prototype as any).name = tag return O.BaseEffectError as any }