Claude
Skills
Sign in
Back

effect-core-patterns

Included with Lifetime
$97 forever

Use when Effect core patterns including Effect<A, E, R> type, succeed, fail, sync, promise, and Effect.gen for composing effects. Use for basic Effect operations.

General

What this skill does


# Effect Core Patterns

Master the core Effect patterns for building type-safe, composable applications
with Effect. This skill covers the Effect type, constructors, and composition
patterns using Effect.gen.

## The Effect Type

The Effect type has three type parameters:

```typescript
Effect<Success, Error, Requirements>
```

- **Success (A)**: The type of value that an effect can succeed with
- **Error (E)**: The expected errors that can occur (use `never` for no errors)
- **Requirements (R)**: The contextual dependencies required (use `never` for no dependencies)

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

// Effect that succeeds with number, never fails, no requirements
const simpleEffect: Effect.Effect<number, never, never> = Effect.succeed(42)

// Effect that can fail with string error
const failableEffect: Effect.Effect<number, string, never> =
  Effect.fail("Something went wrong")

// Effect that requires a UserService
interface UserService {
  getUser: (id: string) => Effect.Effect<User, DbError, never>
}

const effectWithDeps: Effect.Effect<User, DbError, UserService> =
  Effect.gen(function* () {
    const userService = yield* Effect.service(UserService)
    const user = yield* userService.getUser("123")
    return user
  })
```

## Creating Effects

### Effect.succeed - Always Succeeds

Use when you have a pure value and need an Effect:

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

const result = Effect.succeed(42)
// Effect<number, never, never>

const user = Effect.succeed({ id: "1", name: "Alice" })
// Effect<User, never, never>

// Void effect (produces no useful value)
const voidEffect = Effect.succeed(undefined)
// Effect<void, never, never>
```

### Effect.fail - Expected Failure

Use for recoverable, expected errors:

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

interface ValidationError {
  _tag: "ValidationError"
  message: string
}

const validateAge = (age: number): Effect.Effect<number, ValidationError, never> => {
  if (age < 0) {
    return Effect.fail({
      _tag: "ValidationError",
      message: "Age must be positive"
    })
  }
  return Effect.succeed(age)
}

// Usage with Effect.gen
const program = Effect.gen(function* () {
  const age = yield* validateAge(-5) // This will fail
  return age
})
```

### Effect.sync - Synchronous Side Effects

Use for synchronous operations with side effects:

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

// Reading from a mutable variable
let counter = 0

const incrementCounter = Effect.sync(() => {
  counter++
  return counter
})

// Logging
const log = (message: string) =>
  Effect.sync(() => {
    console.log(message)
  })

// Current timestamp
const now = Effect.sync(() => Date.now())

// IMPORTANT: The function should not throw
// Thrown errors become "defects" (unexpected failures)
```

### Effect.try - Synchronous Operations That May Fail

Use for sync operations that might throw:

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

// Parse JSON safely
const parseJSON = (text: string): Effect.Effect<unknown, Error, never> =>
  Effect.try(() => JSON.parse(text))

// With custom error mapping
interface ParseError {
  _tag: "ParseError"
  message: string
}

const parseJSONCustom = (text: string): Effect.Effect<unknown, ParseError, never> =>
  Effect.try({
    try: () => JSON.parse(text),
    catch: (error) => ({
      _tag: "ParseError",
      message: error instanceof Error ? error.message : String(error)
    })
  })

// Usage
const program = Effect.gen(function* () {
  const data = yield* parseJSON('{"name": "Alice"}')
  return data
})
```

### Effect.promise - Async Operations (No Errors)

Use for promises that should never reject:

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

// Delayed execution
const delay = (ms: number): Effect.Effect<void, never, never> =>
  Effect.promise(() =>
    new Promise<void>((resolve) => setTimeout(resolve, ms))
  )

// Fetch with assumption it won't fail
const fetchData = (url: string): Effect.Effect<Response, never, never> =>
  Effect.promise(() => fetch(url))

// IMPORTANT: If promise rejects, it becomes a "defect"
// Use Effect.tryPromise for operations that can fail
```

### Effect.tryPromise - Async Operations That May Fail

Use for promises that might reject:

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

interface NetworkError {
  _tag: "NetworkError"
  message: string
  statusCode?: number
}

const fetchUser = (id: string): Effect.Effect<User, NetworkError, never> =>
  Effect.tryPromise({
    try: async () => {
      const response = await fetch(`/api/users/${id}`)
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`)
      }
      return response.json()
    },
    catch: (error) => ({
      _tag: "NetworkError",
      message: error instanceof Error ? error.message : String(error),
      statusCode: error instanceof Error && 'status' in error
        ? (error as any).status
        : undefined
    })
  })

// Simplified version (errors become UnknownException)
const fetchUserSimple = (id: string): Effect.Effect<User, UnknownException, never> =>
  Effect.tryPromise(() => fetch(`/api/users/${id}`).then(r => r.json()))
```

### Effect.async - Callback-Based APIs

Use for wrapping callback-style APIs:

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

// Wrap setTimeout
const sleep = (ms: number): Effect.Effect<void, never, never> =>
  Effect.async<void>((resume) => {
    const timeoutId = setTimeout(() => {
      resume(Effect.succeed(undefined))
    }, ms)

    // Optional cleanup on interruption
    return Effect.sync(() => {
      clearTimeout(timeoutId)
    })
  })

// Wrap Node.js callback API
interface FileError {
  _tag: "FileError"
  message: string
}

const readFile = (path: string): Effect.Effect<string, FileError, never> =>
  Effect.async<string, FileError>((resume) => {
    fs.readFile(path, 'utf8', (error, data) => {
      if (error) {
        resume(Effect.fail({
          _tag: "FileError",
          message: error.message
        }))
      } else {
        resume(Effect.succeed(data))
      }
    })
  })
```

## Composing Effects with Effect.gen

Effect.gen allows you to write effect code using generator syntax:

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

// Basic composition
const program = Effect.gen(function* () {
  const a = yield* Effect.succeed(10)
  const b = yield* Effect.succeed(20)
  return a + b
})

// With error handling
const programWithErrors = Effect.gen(function* () {
  const age = yield* validateAge(25)
  const user = yield* createUser({ age })
  return user
})

// Sequential operations
const fetchUserProfile = (userId: string) =>
  Effect.gen(function* () {
    const user = yield* fetchUser(userId)
    const posts = yield* fetchPosts(user.id)
    const comments = yield* fetchComments(user.id)
    return { user, posts, comments }
  })

// Using control flow
const processData = (data: unknown) =>
  Effect.gen(function* () {
    const validated = yield* validateData(data)

    if (validated.type === "user") {
      const user = yield* createUser(validated)
      return { type: "user", user }
    } else {
      const post = yield* createPost(validated)
      return { type: "post", post }
    }
  })

// Error handling with short-circuiting
const safeDivide = (a: number, b: number) =>
  Effect.gen(function* () {
    if (b === 0) {
      yield* Effect.fail({ _tag: "DivideByZero" })
      return // Explicit return for type narrowing
    }
    return a / b
  })
```

## Running Effects

### Effect.runSync - Synchronous Execution

Use for effects with no async operations or requirements:

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

const result = Effect.runSync(Effect.succeed(42))
// 42

// Throws if effect can fail
try {
  Effect.runSync(Effect.fail("error"))
} catch (error) {
  // Caught
}

// CANNOT use with async effects or requirements
// Effect.runSync(Effect.promise(() => fetch("..."))) // Runtime error!
```

### Effect.runPromise - Async Execution

Use for async effects wi

Related in General