Documentation Index
Fetch the complete documentation index at: https://effect-ts-effect-smol.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Effect provides immutable data structures with built-in equality, hashing, and pattern matching capabilities. These structures form the foundation for building type-safe domain models.
Overview
The Data module provides:
- Immutable classes: Value types with structural equality
- Tagged classes: Discriminated unions with
_tag fields
- Tagged enums: Multi-variant unions with constructors
- Error classes: Yieldable error types for Effect integration
Data.Class
Base class for immutable data types with structural equality.
Basic Usage
import { Data, Equal } from "effect"
class Person extends Data.Class<{ readonly name: string; readonly age: number }> {}
const alice1 = new Person({ name: "Alice", age: 30 })
const alice2 = new Person({ name: "Alice", age: 30 })
const bob = new Person({ name: "Bob", age: 25 })
console.log(Equal.equals(alice1, alice2)) // true
console.log(Equal.equals(alice1, bob)) // false
With Methods
import { Data } from "effect"
class Point extends Data.Class<{ readonly x: number; readonly y: number }> {
distance(other: Point): number {
const dx = this.x - other.x
const dy = this.y - other.y
return Math.sqrt(dx * dx + dy * dy)
}
}
const p1 = new Point({ x: 0, y: 0 })
const p2 = new Point({ x: 3, y: 4 })
console.log(p1.distance(p2)) // 5
Data.TaggedClass
Like Data.Class but automatically adds a _tag discriminator field.
import { Data } from "effect"
class User extends Data.TaggedClass("User")<{
readonly id: number
readonly name: string
}> {}
class Guest extends Data.TaggedClass("Guest")<{
readonly sessionId: string
}> {}
const user = new User({ id: 1, name: "Alice" })
console.log(user._tag) // "User"
const guest = new Guest({ sessionId: "abc123" })
console.log(guest._tag) // "Guest"
Data.TaggedEnum
Define discriminated unions with multiple variants.
Basic Tagged Enum
import { Data } from "effect"
type Shape = Data.TaggedEnum<{
Circle: { readonly radius: number }
Rectangle: { readonly width: number; readonly height: number }
Triangle: { readonly base: number; readonly height: number }
}>
const { Circle, Rectangle, Triangle } = Data.taggedEnum<Shape>()
const circle = Circle({ radius: 5 })
const rect = Rectangle({ width: 10, height: 20 })
console.log(circle._tag) // "Circle"
console.log(rect._tag) // "Rectangle"
Pattern Matching
import { Data } from "effect"
type Shape = Data.TaggedEnum<{
Circle: { readonly radius: number }
Rectangle: { readonly width: number; readonly height: number }
}>
const { Circle, Rectangle, $match } = Data.taggedEnum<Shape>()
const calculateArea = $match({
Circle: ({ radius }) => Math.PI * radius ** 2,
Rectangle: ({ width, height }) => width * height
})
const circle = Circle({ radius: 5 })
const rect = Rectangle({ width: 10, height: 20 })
console.log(calculateArea(circle)) // 78.54
console.log(calculateArea(rect)) // 200
Type Guards
import { Data } from "effect"
type Result = Data.TaggedEnum<{
Success: { readonly value: string }
Failure: { readonly error: string }
}>
const { Success, Failure, $is } = Data.taggedEnum<Result>()
const result = Success({ value: "data" })
if ($is("Success")(result)) {
console.log(result.value) // TypeScript knows this is Success
}
if ($is("Failure")(result)) {
console.log(result.error) // This branch won't execute
}
Error Classes
Yieldable error types that integrate with Effect’s error handling.
Data.Error
import { Data, Effect } from "effect"
class NetworkError extends Data.Error<{
readonly message: string
readonly statusCode: number
}> {}
const program = Effect.gen(function*() {
// Can yield errors directly
return yield* new NetworkError({
message: "Connection failed",
statusCode: 500
})
})
// Handle the error
const handled = program.pipe(
Effect.catchAll((error) =>
Effect.log(`Error: ${error.message} (${error.statusCode})`)
)
)
Data.TaggedError
import { Data, Effect, Schema } from "effect"
class ValidationError extends Data.TaggedError("ValidationError")<{
readonly field: string
readonly message: string
}> {}
class DatabaseError extends Data.TaggedError("DatabaseError")<{
readonly query: string
readonly cause: string
}> {}
const program = Effect.gen(function*() {
return yield* new ValidationError({
field: "email",
message: "Invalid email format"
})
})
// Tag-based error handling
const handled = program.pipe(
Effect.catchTag("ValidationError", (error) =>
Effect.log(`Validation failed on ${error.field}: ${error.message}`)
),
Effect.catchTag("DatabaseError", (error) =>
Effect.log(`Database error: ${error.cause}`)
)
)
Schema Integration
Use Schema.TaggedErrorClass for runtime-validated errors:
import { Effect, Schema } from "effect"
class FileError extends Schema.TaggedErrorClass<FileError>()("FileError", {
path: Schema.String,
reason: Schema.Literal("not_found", "permission_denied", "corrupted")
}) {}
const program = Effect.gen(function*() {
return yield* new FileError({
path: "/etc/config",
reason: "permission_denied"
})
})
Working with Collections
HashMap
import { Data, HashMap } from "effect"
class UserId extends Data.Class<{ readonly id: number }> {}
let map = HashMap.empty<UserId, string>()
map = HashMap.set(map, new UserId({ id: 1 }), "Alice")
map = HashMap.set(map, new UserId({ id: 2 }), "Bob")
const alice = HashMap.get(map, new UserId({ id: 1 }))
console.log(alice) // Some("Alice")
HashSet
import { Data, HashSet } from "effect"
class Email extends Data.Class<{ readonly address: string }> {}
let set = HashSet.empty<Email>()
set = HashSet.add(set, new Email({ address: "alice@example.com" }))
set = HashSet.add(set, new Email({ address: "bob@example.com" }))
const hasAlice = HashSet.has(
set,
new Email({ address: "alice@example.com" })
)
console.log(hasAlice) // true
Common Patterns
Domain Models
import { Data } from "effect"
class Money extends Data.Class<{
readonly amount: number
readonly currency: string
}> {
add(other: Money): Money {
if (this.currency !== other.currency) {
throw new Error("Currency mismatch")
}
return new Money({
amount: this.amount + other.amount,
currency: this.currency
})
}
}
const price1 = new Money({ amount: 10, currency: "USD" })
const price2 = new Money({ amount: 5, currency: "USD" })
const total = price1.add(price2)
console.log(total) // Money { amount: 15, currency: "USD" }
State Machines
import { Data } from "effect"
type ConnectionState = Data.TaggedEnum<{
Disconnected: {}
Connecting: { readonly attemptCount: number }
Connected: { readonly connectionId: string }
Failed: { readonly error: string }
}>
const { Disconnected, Connecting, Connected, Failed, $match } =
Data.taggedEnum<ConnectionState>()
const handleState = $match({
Disconnected: () => "Starting connection...",
Connecting: ({ attemptCount }) => `Attempt ${attemptCount}...`,
Connected: ({ connectionId }) => `Connected (${connectionId})",
Failed: ({ error }) => `Connection failed: ${error}`
})
const state = Connecting({ attemptCount: 2 })
console.log(handleState(state)) // "Attempt 2..."
ADT with Methods
import { Data } from "effect"
type List<A> = Data.TaggedEnum<{
Nil: {}
Cons: { readonly head: A; readonly tail: List<A> }
}>
const makeList = <A>() => {
const { Nil, Cons, $match } = Data.taggedEnum<List<A>>()
const length = $match({
Nil: () => 0,
Cons: ({ tail }) => 1 + length(tail)
})
return { Nil, Cons, length }
}
const { Nil, Cons, length } = makeList<number>()
const list = Cons({
head: 1,
tail: Cons({ head: 2, tail: Cons({ head: 3, tail: Nil({}) }) })
})
console.log(length(list)) // 3
Best Practices
- Use Data.Class for value types: Prefer immutable data classes over plain objects
- Use TaggedEnum for discriminated unions: Better than manual discriminated unions
- Leverage pattern matching: Use $match for exhaustive case handling
- Use TaggedError for domain errors: Integrate errors with Effect’s error handling
- Keep data classes simple: Move complex logic to separate functions
- Use structural equality: Take advantage of built-in equality for value types
Next Steps
- Learn about Schema for runtime validation
- Explore Effect for error handling
- Understand how to build domain models with Effect