Effect-TS Core Library

3.21.1 · active · verified Sun Apr 19

Effect-TS is a robust, type-safe functional programming library for TypeScript, providing a "missing standard library" for building highly concurrent, resilient, and performant applications. It centers around the `Effect` data type, which represents a description of a computation that may require resources (R), may fail with an error (E), and may succeed with a value (A). The library promotes a functional-first approach, emphasizing immutability, explicit error handling, and structured concurrency, leveraging TypeScript's type system to ensure correctness at compile-time. Currently stable at version 3.x (e.g., 3.21.1), `effect` maintains a regular release cadence with frequent patch and minor updates, reflecting active development and continuous improvement. It differentiates itself through its comprehensive ecosystem of modules (e.g., `Effect.Layer`, `Effect.Schema`, `Effect.Stream`) that integrate seamlessly, offering a complete solution for complex application logic, asynchronous operations, and resource management without runtime exceptions.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates creating and composing Effects, handling different types of errors with custom error classes, using `pipe` for composition, applying retry logic, and running the Effect to a Promise, including a simulated database defect.

import { Effect, Console, pipe, Duration, Schedule } from 'effect';

interface User {
  id: number;
  name: string;
  email: string;
}

// Define a custom error type for better type safety
class UserNotFoundError extends Effect.Error('UserNotFoundError')<{ userId: number }> {}
class DatabaseConnectionError extends Effect.Error('DatabaseConnectionError')<{ message: string }> {}

// Simulate fetching a user from a database
const fetchUserFromDB = (userId: number): Effect.Effect<User, UserNotFoundError | DatabaseConnectionError, never> =>
  Effect.sync(() => {
    if (userId === 1) {
      return { id: 1, name: 'Alice', email: 'alice@example.com' };
    } else if (userId === 99) {
      throw new Error('Failed to connect to DB'); // Simulate a defect
    }
    return Effect.fail(new UserNotFoundError({ userId }));
  }).pipe(
    Effect.catchAllDefect((error) =>
      Effect.fail(new DatabaseConnectionError({ message: String(error) }))
    )
  );

const program = pipe(
  fetchUserFromDB(1), // Try to fetch user with ID 1
  Effect.tap((user) => Console.log(`Fetched user: ${user.name}`)),
  Effect.flatMap(() => fetchUserFromDB(2)), // Try to fetch user with ID 2 (will fail)
  Effect.tapError((error) =>
    error._tag === 'UserNotFoundError'
      ? Console.error(`Error: User with ID ${error.userId} not found.`)
      : Console.error(`Critical Error: ${error.message}`)
  ),
  Effect.retry(Schedule.exponential(Duration.seconds(1), 3)), // Retry failed operations with exponential backoff
  Effect.matchEffect({ // Handle both success and failure paths explicitly
    onFailure: (error) => Console.error(`Final failure: ${error._tag}`),
    onSuccess: (user) => Console.log(`Final success (should not happen for user 2, unless retries succeed): ${user.name}`),
  })
);

// Run the Effect program
Effect.runPromise(program).then(() => Console.log('Program finished.')).catch(console.error);

view raw JSON →