Data.ts
Data.ts overview
Section titled “Data.ts overview”Defines helpers for small immutable data models.
This module helps create plain classes, tagged classes, tagged unions, and
typed errors with readonly fields. Tagged values carry a _tag field, which
makes them easy to narrow with pattern matching or simple checks. These
helpers are commonly used for domain values and errors in Effect programs.
Since v2.0.0
Exports Grouped by Category
Section titled “Exports Grouped by Category”constructors
Section titled “constructors”Provides a base class for immutable data types.
When to use
Use when you need a lightweight immutable value type with .pipe() support.
Details
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. Instances are Readonly and Pipeable.
Example (Defining a value class)
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))// trueSee
TaggedClass— adds a_tagfieldError— yieldable error variant
Signature
declare const Class: new <A extends Record<string, any> = {}>( args: Types.VoidIfEmpty<{ readonly [P in keyof A]: A[P] }>) => Readonly<A> & Pipeable.PipeableSince v2.0.0
Provides a base class for yieldable errors.
When to use
Use when you need yieldable errors that do not need tag-based discrimination.
Details
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. If a message
field is provided, it becomes the error’s .message.
Example (Defining a yieldable error)
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 NetworkErrorEffect.runSync(Effect.exit(program))See
TaggedError— adds a_tagforEffect.catchTagClass— non-error data class
Signature
declare const Error: new <A extends Record<string, any> = {}>( args: Types.VoidIfEmpty<{ readonly [P in keyof A]: A[P] }>) => Cause.YieldableError & Readonly<A>Since v2.0.0
TaggedClass
Section titled “TaggedClass”Provides a base class for immutable data types with a _tag discriminator.
When to use
Use when you need a single-variant tagged type or an ad-hoc discriminator.
Details
Like Class, but the resulting instances also carry a
readonly _tag: Tag property. The _tag is excluded from the constructor
argument.
Example (Defining a tagged class)
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
Class— without a_tagTaggedError— tagged error variantTaggedEnum— multi-variant unions
Signature
declare const TaggedClass: <Tag extends string>( tag: Tag) => new <A extends Record<string, any> = {}>( args: Types.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => Readonly<A> & { readonly _tag: Tag } & Pipeable.PipeableSince v2.0.0
TaggedError
Section titled “TaggedError”Creates a tagged error class with a _tag discriminator.
When to use
Use when you need domain errors with discriminated-union handling.
Details
Like 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. Yielding an instance
inside Effect.gen fails the effect with this error.
Example (Recovering by tag)
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
Error— without a_tagTaggedClass— tagged class that is not an error
Signature
declare const TaggedError: <Tag extends string>( tag: Tag) => new <A extends Record<string, any> = {}>( args: Types.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => Cause.YieldableError & { readonly _tag: Tag } & Readonly<A>Since v2.0.0
taggedEnum
Section titled “taggedEnum”Creates constructors and matchers for a TaggedEnum type.
When to use
Use when you model a closed union with plain data objects and want construction, tag checks, and exhaustive matching from the same definition.
Details
Returns an object with:
- One constructor per variant (keyed by tag name)
$is(tag)— returns a type-guard function that checks only the_tagfield$match— exhaustive pattern matching (data-first or data-last)
Gotchas
- Constructors produce plain objects, not class instances.
$is(tag)only checks the_tagfield, not the full structure. It relies on the tag being globally unique and the value being produced by your constructors. For untrusted input, validate with theSchemamodule first.
Example (Creating and matching tagged enum values)
import { Data } from "effect"
type HttpError = Data.TaggedEnum<{ BadRequest: { readonly message: string } NotFound: { readonly url: string }}>
const { BadRequest, NotFound, $is, $match } = Data.taggedEnum<HttpError>()
const err = NotFound({ url: "/missing" })
// Type guardconsole.log($is("NotFound")(err)) // true
// Pattern matchingconst msg = $match(err, { BadRequest: (e) => e.message, NotFound: (e) => `${e.url} not found`})console.log(msg) // "/missing not found"Example (Defining a generic tagged enum)
import { Data } from "effect"
type MyResult<E, A> = Data.TaggedEnum<{ Failure: { readonly error: E } Success: { readonly value: A }}>interface MyResultDef extends Data.TaggedEnum.WithGenerics<2> { readonly taggedEnum: MyResult<this["A"], this["B"]>}const { Failure, Success } = Data.taggedEnum<MyResultDef>()
const ok = Success({ value: 42 })// ok: { readonly _tag: "Success"; readonly value: number }See
TaggedEnum— the type-level companionTaggedEnum.Constructor— the returned object typeTaggedEnum.WithGenerics— generic enum support
Signature
declare const taggedEnum: { <Z extends TaggedEnum.WithGenerics<1>>(): Types.Simplify< { readonly [Tag in Z["taggedEnum"]["_tag"]]: <A>( args: TaggedEnum.Args<TaggedEnum.Kind<Z, A>, Tag, Extract<TaggedEnum.Kind<Z, A>, { readonly _tag: Tag }>> ) => TaggedEnum.Value<TaggedEnum.Kind<Z, A>, Tag> } & TaggedEnum.GenericMatchers<Z> > <Z extends TaggedEnum.WithGenerics<2>>(): Types.Simplify< { readonly [Tag in Z["taggedEnum"]["_tag"]]: <A, B>( args: TaggedEnum.Args<TaggedEnum.Kind<Z, A, B>, Tag, Extract<TaggedEnum.Kind<Z, A, B>, { readonly _tag: Tag }>> ) => TaggedEnum.Value<TaggedEnum.Kind<Z, A, B>, Tag> } & TaggedEnum.GenericMatchers<Z> > <Z extends TaggedEnum.WithGenerics<3>>(): Types.Simplify< { readonly [Tag in Z["taggedEnum"]["_tag"]]: <A, B, C>( args: TaggedEnum.Args< TaggedEnum.Kind<Z, A, B, C>, Tag, Extract<TaggedEnum.Kind<Z, A, B, C>, { readonly _tag: Tag }> > ) => TaggedEnum.Value<TaggedEnum.Kind<Z, A, B, C>, Tag> } & TaggedEnum.GenericMatchers<Z> > <Z extends TaggedEnum.WithGenerics<4>>(): Types.Simplify< { readonly [Tag in Z["taggedEnum"]["_tag"]]: <A, B, C, D>( args: TaggedEnum.Args< TaggedEnum.Kind<Z, A, B, C, D>, Tag, Extract<TaggedEnum.Kind<Z, A, B, C, D>, { readonly _tag: Tag }> > ) => TaggedEnum.Value<TaggedEnum.Kind<Z, A, B, C, D>, Tag> } & TaggedEnum.GenericMatchers<Z> > <A extends { readonly _tag: string }>(): TaggedEnum.Constructor<A>}Since v2.0.0
models
Section titled “models”TaggedEnum (type alias)
Section titled “TaggedEnum (type alias)”Transforms a record of variant definitions into a discriminated union type.
When to use
Use when you have two or more variants that share a common _tag discriminator.
Details
Each key in the record becomes a variant with readonly _tag set to that
key. Use with taggedEnum to get constructors and matchers.
Gotchas
Variant records must not include a _tag property; it is added automatically.
Example (Defining a tagged enum)
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<HttpError>()
const err = BadRequest({ status: 400, message: "missing id" })console.log(err._tag)// "BadRequest"See
taggedEnum— constructors and matchers for aTaggedEnumTaggedEnum.WithGenerics— generic tagged enumsTaggedEnum.Constructor— the constructor object type
Signature
type TaggedEnum<A> = keyof A extends infer Tag ? Tag extends keyof A ? Types.Simplify<{ readonly _tag: Tag } & { readonly [K in keyof A[Tag]]: A[Tag][K] }> : never : neverSince v2.0.0
TaggedEnum (namespace)
Section titled “TaggedEnum (namespace)”Namespace for TaggedEnum utility types.
When to use
Use to reference utility types for constructing, extracting, and matching
TaggedEnum variants.
Details
Provides helper types for:
- Generic tagged enums (
TaggedEnum.WithGenerics,TaggedEnum.Kind) - Extracting constructor arguments (
TaggedEnum.Args) and variant values (TaggedEnum.Value) - Full constructor objects (
TaggedEnum.Constructor)
Since v2.0.0
WithGenerics (interface)
Section titled “WithGenerics (interface)”Defines a tagged enum shape that accepts generic type parameters.
When to use
Use when variant payloads need to be parameterized, such as Result<E, A>.
Details
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).
Example (Defining a generic tagged enum)
import { Data } from "effect"
type MyResult<E, A> = Data.TaggedEnum<{ Failure: { readonly error: E } Success: { readonly value: A }}>
interface MyResultDef extends Data.TaggedEnum.WithGenerics<2> { readonly taggedEnum: MyResult<this["A"], this["B"]>}
const { Failure, Success } = Data.taggedEnum<MyResultDef>()
const ok = Success({ value: 42 })// ok: { readonly _tag: "Success"; readonly value: number }See
Kind— apply concrete types to aWithGenericsdefinitiontaggedEnum— constructors and matchers
Signature
export interface WithGenerics<Count extends number> { readonly taggedEnum: { readonly _tag: string } readonly numberOfGenerics: Count
readonly A: unknown readonly B: unknown readonly C: unknown readonly D: unknown}Since v2.0.0
GenericMatchers (interface)
Section titled “GenericMatchers (interface)”Type-guard and pattern-matching interface for generic tagged enums.
When to use
Use to type the $is and $match helpers for generic tagged enums.
Details
This is the $is / $match portion of the object returned by
taggedEnum when used with a WithGenerics definition.
See
Constructor— the non-generic equivalent
Signature
export interface GenericMatchers<Z extends WithGenerics<number>> { readonly $is: <Tag extends Z["taggedEnum"]["_tag"]>( tag: Tag ) => { <T extends TaggedEnum.Kind<Z, any, any, any, any>>(u: T): u is T & { readonly _tag: Tag } (u: unknown): u is Extract<TaggedEnum.Kind<Z>, { readonly _tag: Tag }> } readonly $match: { < A, B, C, D, Cases extends { readonly [Tag in Z["taggedEnum"]["_tag"]]: ( args: Extract<TaggedEnum.Kind<Z, A, B, C, D>, { readonly _tag: Tag }> ) => any } >( cases: Cases ): (self: TaggedEnum.Kind<Z, A, B, C, D>) => Unify<ReturnType<Cases[Z["taggedEnum"]["_tag"]]>> < A, B, C, D, Cases extends { readonly [Tag in Z["taggedEnum"]["_tag"]]: ( args: Extract<TaggedEnum.Kind<Z, A, B, C, D>, { readonly _tag: Tag }> ) => any } >( self: TaggedEnum.Kind<Z, A, B, C, D>, cases: Cases ): Unify<ReturnType<Cases[Z["taggedEnum"]["_tag"]]>> }}Since v3.2.0
Kind (type alias)
Section titled “Kind (type alias)”Applies concrete type arguments to a WithGenerics definition, producing
the resulting tagged union type.
When to use
Use to refer to a specific instantiation of a generic tagged enum in type signatures.
Example (Applying generics)
import type { Data } from "effect"
type Option<A> = Data.TaggedEnum<{ None: {} Some: { readonly value: A }}>interface OptionDef extends Data.TaggedEnum.WithGenerics<1> { readonly taggedEnum: Option<this["A"]>}
// Resolve to the concrete union for `string`type StringOption = Data.TaggedEnum.Kind<OptionDef, string>// { _tag: "None" } | { _tag: "Some"; value: string }See
WithGenerics— define the generic shape
Signature
type Kind<Z, A, B, C, D> = (Z & { readonly A: A readonly B: B readonly C: C readonly D: D})["taggedEnum"]Since v2.0.0
Args (type alias)
Section titled “Args (type alias)”Extracts the constructor argument type for a specific variant of a tagged union.
When to use
Use to derive the argument object expected by a constructor for one tagged union variant.
Details
Returns void if the variant has no fields beyond _tag.
Example (Extracting variant args)
import type { Data } from "effect"
type Result = { readonly _tag: "Ok"; readonly value: number } | { readonly _tag: "Err"; readonly error: string }
type OkArgs = Data.TaggedEnum.Args<Result, "Ok">// { readonly value: number }
type ErrArgs = Data.TaggedEnum.Args<Result, "Err">// { readonly error: string }See
Value— extracts the full variant type (including_tag)
Signature
type Args<A, K, E> = { readonly [K in keyof E as K extends "_tag" ? never : K]: E[K]} extends infer T ? Types.VoidIfEmpty<T> : neverSince v2.0.0
Value (type alias)
Section titled “Value (type alias)”Extracts the full variant type (including _tag) for a specific tag.
When to use
Use to select one full tagged-union variant by its _tag value.
Example (Extracting a variant type)
import type { Data } from "effect"
type Result = { readonly _tag: "Ok"; readonly value: number } | { readonly _tag: "Err"; readonly error: string }
type OkVariant = Data.TaggedEnum.Value<Result, "Ok">// { readonly _tag: "Ok"; readonly value: number }See
Args— extracts fields without_tag
Signature
type Value<A, K> = Extract<A, { readonly _tag: K }>Since v2.0.0
Constructor (type alias)
Section titled “Constructor (type alias)”The full constructors-and-matchers object type returned by taggedEnum.
When to use
Use when you want to annotate an exported constructor bundle so downstream code keeps exact variant constructors and exhaustive matching.
Details
Includes:
- A constructor function for each variant (keyed by tag name)
$is(tag)— returns a type-guard that checks only the_tagfield; safe when the tag is globally unique and the value was produced by your constructors. For untrusted input, validate with theSchemamodule first.$match— exhaustive pattern matching (data-last or data-first)
Example (Using the constructor object)
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<Shape>()
const shape = Circle({ radius: 10 })
// Type guardif ($is("Circle")(shape)) { console.log(shape.radius)}
// Pattern matchingconst label = $match(shape, { Circle: (s) => `circle r=${s.radius}`, Rect: (s) => `rect ${s.w}x${s.h}`})See
taggedEnum— creates constructors and matchers
Signature
type Constructor<A> = Types.Simplify< { readonly [Tag in A["_tag"]]: ConstructorFrom<Extract<A, { readonly _tag: Tag }>, "_tag"> } & { readonly $is: <Tag extends A["_tag"]>(tag: Tag) => (u: unknown) => u is Extract<A, { readonly _tag: Tag }> readonly $match: { < Cases extends { readonly [Tag in A["_tag"]]: (args: Extract<A, { readonly _tag: Tag }>) => any } >( cases: Cases ): (value: A) => Unify<ReturnType<Cases[A["_tag"]]>> < Cases extends { readonly [Tag in A["_tag"]]: (args: Extract<A, { readonly _tag: Tag }>) => any } >( value: A, cases: Cases ): Unify<ReturnType<Cases[A["_tag"]]>> } }>Since v3.1.0
ConstructorFrom (type alias)
Section titled “ConstructorFrom (type alias)”Function type that constructs a tagged-union variant from its fields,
excluding the keys listed in Tag.
When to use
Use to type an individual constructor for one tagged-union variant.
Details
The constructor returns the full variant type A. If no fields remain
after excluding Tag keys, the constructor argument type becomes void.
Signature
type ConstructorFrom<A, Tag> = ( args: Types.VoidIfEmpty<{ readonly [P in keyof A as P extends Tag ? never : P]: A[P] }>) => ASince v4.0.0