home / skills / andrueandersoncs / claude-skill-effect-ts / data-types

data-types skill

/skills/data-types

This skill helps you understand Effect's built-in data types and structures, enabling precise reasoning about Option, Either, Cause, Exit, and more.

npx playbooks add skill andrueandersoncs/claude-skill-effect-ts --skill data-types

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
7.3 KB
---
name: Data Types
description: This skill should be used when the user asks about "Effect Option", "Effect Either", "Option.some", "Option.none", "Either.left", "Either.right", "Cause", "Exit", "Chunk", "Data", "Data.TaggedEnum", "Data.Class", "Duration", "DateTime", "HashMap", "HashSet", "Redacted", or needs to understand Effect's built-in data types and functional data structures.
version: 1.0.0
---

# Data Types in Effect

## Overview

Effect provides immutable, type-safe data structures:

- **Option** - Represents optional values (Some/None)
- **Either** - Represents success/failure (Right/Left)
- **Cause** - Detailed failure information
- **Exit** - Effect execution result
- **Data** - Value equality for classes
- **Chunk** - Immutable indexed sequence
- **Duration** - Time spans
- **DateTime** - Date/time handling

## Option

Represents a value that may or may not exist:

```typescript
import { Option } from "effect"

const some = Option.some(42)
const none = Option.none()

const fromNull = Option.fromNullable(maybeNull)

const result = Option.match(option, {
  onNone: () => "No value",
  onSome: (value) => `Got: ${value}`
})

const value = Option.getOrElse(option, () => defaultValue)

const doubled = Option.map(option, (n) => n * 2)

const chained = Option.flatMap(option, (n) =>
  n > 0 ? Option.some(n) : Option.none()
)

const positive = Option.filter(option, (n) => n > 0)
```

### Option with Effect

```typescript
const program = Effect.gen(function* () {
  const maybeUser = yield* findUser(id)

  // Convert Option to Effect
  const user = yield* Option.match(maybeUser, {
    onNone: () => Effect.fail(new UserNotFound()),
    onSome: Effect.succeed
  })

  // Or use Effect.fromOption
  const user = yield* maybeUser.pipe(
    Effect.fromOption,
    Effect.mapError(() => new UserNotFound())
  )
})
```

## Either

Represents a value that is either Left (failure) or Right (success):

```typescript
import { Either } from "effect"

const right = Either.right(42)
const left = Either.left("error")

const result = Either.match(either, {
  onLeft: (error) => `Error: ${error}`,
  onRight: (value) => `Success: ${value}`
})

const doubled = Either.map(either, (n) => n * 2)

const mapped = Either.mapLeft(either, (e) => new Error(e))

const both = Either.mapBoth(either, {
  onLeft: (e) => new Error(e),
  onRight: (n) => n * 2
})

const chained = Either.flatMap(either, (n) =>
  n > 0 ? Either.right(n) : Either.left("negative")
)

const value = Either.getOrThrow(either)
```

## Cause

Complete failure information for an Effect:

```typescript
import { Cause } from "effect"

Cause.fail(error)
Cause.die(defect)
Cause.interrupt(id)
Cause.empty
Cause.sequential(c1, c2)
Cause.parallel(c1, c2)

Cause.isFailure(cause)
Cause.isDie(cause)
Cause.isInterrupt(cause)

const failures = Cause.failures(cause)
const defects = Cause.defects(cause)

const message = Cause.pretty(cause)
```

## Exit

The result of running an Effect:

```typescript
import { Exit } from "effect"

Exit.succeed(value)
Exit.fail(cause)

const result = Exit.match(exit, {
  onFailure: (cause) => `Failed: ${Cause.pretty(cause)}`,
  onSuccess: (value) => `Succeeded: ${value}`
})

Exit.isSuccess(exit)
Exit.isFailure(exit)

const value = Exit.getOrElse(exit, () => defaultValue)

const mapped = Exit.map(exit, (a) => a * 2)
```

## Data - Value Equality

Create classes with structural equality:

```typescript
import { Data, Schema } from "effect"

// Tagged class
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 })

alice1 === alice2  // false (reference)
Equal.equals(alice1, alice2)  // true (structural)

// Tagged errors (used with Effect.fail)
// Use Schema.TaggedError for domain errors - works with Schema.is(), catchTag, and Match.tag
class UserNotFound extends Schema.TaggedError<UserNotFound>()(
  "UserNotFound",
  { userId: Schema.String }
) {}

// Tagged enum
type Shape = Data.TaggedEnum<{
  Circle: { radius: number }
  Rectangle: { width: number; height: number }
}>
const { Circle, Rectangle } = Data.taggedEnum<Shape>()

const circle = Circle({ radius: 10 })
const rect = Rectangle({ width: 5, height: 3 })
```

## Chunk

Immutable indexed sequence optimized for Effect:

```typescript
import { Chunk } from "effect"

const chunk = Chunk.make(1, 2, 3, 4, 5)
const fromArray = Chunk.fromIterable([1, 2, 3])
const empty = Chunk.empty<number>()

const head = Chunk.head(chunk)
const tail = Chunk.tail(chunk)
const take = Chunk.take(chunk, 2)
const drop = Chunk.drop(chunk, 2)

const doubled = Chunk.map(chunk, (n) => n * 2)
const filtered = Chunk.filter(chunk, (n) => n > 2)
const sum = Chunk.reduce(chunk, 0, (acc, n) => acc + n)

const array = Chunk.toArray(chunk)
const readonlyArray = Chunk.toReadonlyArray(chunk)
```

## Duration

Represent time spans:

```typescript
import { Duration } from "effect"

const ms = Duration.millis(100)
const secs = Duration.seconds(5)
const mins = Duration.minutes(10)
const hours = Duration.hours(2)
const days = Duration.days(1)

const fromString = Duration.decode("5 seconds")

const total = Duration.sum(duration1, duration2)
const remaining = Duration.subtract(total, elapsed)

Duration.greaterThan(a, b)
Duration.lessThanOrEqualTo(a, b)

const milliseconds = Duration.toMillis(duration)
const seconds = Duration.toSeconds(duration)
```

## DateTime

Date and time handling:

```typescript
import { DateTime } from "effect"

const now = DateTime.now

const fromDate = DateTime.fromDate(new Date())

const specific = DateTime.make({
  year: 2024,
  month: 1,
  day: 15,
  hours: 10,
  minutes: 30
})

const tomorrow = DateTime.add(now, { days: 1 })
const lastWeek = DateTime.subtract(now, { weeks: 1 })

const formatted = DateTime.format(now, "yyyy-MM-dd")

const utc = DateTime.setZone(now, "UTC")
const local = DateTime.setZone(now, DateTime.zoneLocal)
```

## HashMap & HashSet

Immutable hash-based collections:

```typescript
import { HashMap, HashSet } from "effect"

const map = HashMap.make(
  ["a", 1],
  ["b", 2],
  ["c", 3]
)

const value = HashMap.get(map, "a")
const updated = HashMap.set(map, "d", 4)
const removed = HashMap.remove(map, "a")

const set = HashSet.make(1, 2, 3, 4, 5)

const has = HashSet.has(set, 3)
const added = HashSet.add(set, 6)
const removed = HashSet.remove(set, 1)
const union = HashSet.union(set1, set2)
const intersection = HashSet.intersection(set1, set2)
```

## Redacted

Protect sensitive values from logging:

```typescript
import { Redacted } from "effect"

const apiKey = Redacted.make("sk-secret-key-123")

console.log(apiKey)
console.log(`Key: ${apiKey}`)

const actual = Redacted.value(apiKey)
```

## Best Practices

1. **Use Option for nullable values** - Explicit handling required
2. **Use Either for validation** - Accumulate errors
3. **Use Schema.TaggedError for Effect errors** - Enables catchTag and Schema.is()
4. **Use Chunk in streaming** - Optimized for Effect operations
5. **Use Redacted for secrets** - Prevents accidental exposure
6. **Use Duration for time** - Type-safe time operations

## Additional Resources

For comprehensive data type documentation, consult `${CLAUDE_PLUGIN_ROOT}/references/llms-full.txt`.

Search for these sections:
- "Option" for optional values
- "Either" for success/failure
- "Cause" for error details
- "Exit" for execution results
- "Data" for value equality
- "Chunk" for sequences
- "DateTime" for date handling

Overview

This skill explains Effect's built-in data types and functional data structures. It covers Option, Either, Cause, Exit, Data (TaggedEnum and Class), Chunk, Duration, DateTime, HashMap, HashSet, and Redacted to help you reason about values, errors, collections, and time in Effect programs.

How this skill works

I summarize each type, show common constructors and matchers, and demonstrate typical transformations and conversions to Effect. The guide explains how to convert Option/Either into Effect failures or successes, inspect Cause and Exit for failure diagnostics, use Data for structural equality and tagged domain errors, and work with immutable collections like Chunk, HashMap, and HashSet. It also covers Duration and DateTime utilities and how to redact secrets for safe logging.

When to use it

  • Use Option for nullable or optionally-present values instead of null/undefined.
  • Use Either for operations that return success or domain-specific failure without throwing.
  • Use Cause and Exit when you need full failure diagnostics from Effects.
  • Use Data.Class or Data.TaggedEnum for value equality and expressive, typed domain models.
  • Use Chunk for indexed, immutable sequences optimized for Effect workflows and streaming.
  • Use Duration/DateTime for type-safe time computations and HashMap/HashSet for immutable hashed collections.

Best practices

  • Always convert Option to Effect when absence should fail the workflow; prefer explicit failure handling.
  • Prefer Either for validation flows so you can map or accumulate errors without exceptions.
  • Use Schema.TaggedError for domain errors to enable pattern matching and catchTag semantics.
  • Prefer Chunk over plain arrays in Effect-heavy code for performance and API consistency.
  • Wrap secrets in Redacted to avoid accidental exposure in logs and debug output.
  • Use Duration and DateTime helpers to avoid manual milliseconds arithmetic and timezone mistakes.

Example use cases

  • Look up optional configuration with Option and fail the Effect with a tagged UserNotFound error when missing.
  • Perform input validation with Either, mapLeft to domain errors, and chain transformations with flatMap.
  • Run an Effect and inspect Exit to pretty-print Cause for logging detailed failure traces.
  • Model immutable domain entities with Data.Class for structural equality checks and use Data.TaggedEnum for algebraic types like shapes.
  • Process a stream of events using Chunk for efficient slicing, mapping, and reductions.
  • Store and query immutable key-value state with HashMap and membership sets with HashSet; redact API keys before logging.

FAQ

How do I turn an Option into a failing Effect?

Match the Option to return Effect.fail on None and Effect.succeed on Some, or use Effect.fromOption and map the error to a domain error.

When should I use Either vs throwing exceptions?

Use Either for predictable, typed errors and validations; prefer throwing only for unrecoverable defects. Either keeps error handling explicit and composable.