Effect-TS는 무료 API를 제공한다: 프로덕션 앱을 위한 TypeScript의 누락된 표준 라이브러리

발행: (2026년 3월 29일 오후 11:09 GMT+9)
3 분 소요
원문: Dev.to

Source: Dev.to

Overview

Effect는 프로덕션 애플리케이션을 위한 표준 라이브러리를 제공하는 TypeScript 라이브러리입니다. 주요 기능은 다음과 같습니다:

  • 타입이 지정된 오류 (어떤 오류가 발생할 수 있는지 정확히 알 수 있음)
  • 의존성 주입 (컨테이너가 필요 없음)
  • 구조화된 동시성 (fibers, 세마포어)
  • 백오프가 포함된 재시도 정책
  • 스키마 검증 (Zod와 비슷하지만 통합되어 있음)
  • 스트림 (반응형 데이터 처리)
  • 내장 트레이싱 및 메트릭스

TypeScript에는 타입이 지정된 오류, 의존성 주입, 재시도, 레이트 리밋, 구조화된 동시성을 다루는 표준 방법이 없습니다. Effect는 이러한 빈틈을 조합 가능하고 타입‑안전한 API로 메워줍니다.

Installation

npm install effect

Basic Usage

import { Effect, Console } from "effect";

const program = Effect.gen(function* () {
  yield* Console.log("Hello from Effect!");
  const result = yield* Effect.succeed(42);
  yield* Console.log(`Result: ${result}`);
});

Effect.runPromise(program);

Typed Errors

import { Effect, Data } from "effect";

class NotFoundError extends Data.TaggedError("NotFoundError") {}

class DatabaseError extends Data.TaggedError("DatabaseError") {}

const findUser = (id: string): Effect.Effect =>
  Effect.gen(function* () {
    const user = yield* queryDatabase(id);
    if (!user) {
      return yield* new NotFoundError({ id });
    }
    return user;
  });

// Handle specific errors
const program = findUser("123").pipe(
  Effect.catchTag("NotFoundError", (e) =>
    Effect.succeed({ name: "Default", id: e.id })
  ),
  Effect.catchTag("DatabaseError", (e) =>
    Effect.fail(new Error(`DB failed: ${e.cause}`))
  ),
);

Dependency Injection with Context & Layers

import { Effect, Context, Layer } from "effect";

class Database extends Context.Tag("Database") Effect.Effect }
>() {}

class Logger extends Context.Tag("Logger") Effect.Effect }
>() {}

const findUsers = Effect.gen(function* () {
  const db = yield* Database;
  const logger = yield* Logger;
  yield* logger.log("Fetching users...");
  return yield* db.query("SELECT * FROM users");
});

// Provide implementations
const DatabaseLive = Layer.succeed(Database, {
  query: (sql) => Effect.succeed([{ id: 1, name: "Alice" }]),
});

const LoggerLive = Layer.succeed(Logger, {
  log: (msg) => Effect.sync(() => console.log(msg)),
});

const MainLive = Layer.merge(DatabaseLive, LoggerLive);

Effect.runPromise(
  findUsers.pipe(Effect.provide(MainLive))
);

Retries, Scheduling, and Concurrency

import { Effect, Schedule } from "effect";

const fetchData = Effect.tryPromise(() =>
  fetch("https://api.example.com/data").then((r) => r.json())
);

// Retry with exponential backoff (up to 5 attempts)
const reliable = fetchData.pipe(
  Effect.retry(
    Schedule.exponential("1 second").pipe(
      Schedule.compose(Schedule.recurs(5))
    )
  ),
);

Running Tasks Concurrently

const tasks = [fetchUser(1), fetchUser(2), fetchUser(3)];

// Run all concurrently (max 3 at a time)
const results = yield* Effect.all(tasks, { concurrency: 3 });

Limiting Concurrency with a Semaphore

// Create a semaphore that allows up to 5 concurrent permits
const semaphore = yield* Effect.makeSemaphore(5);

// Wrap each task to acquire a permit before execution
const limited = tasks.map((task) => semaphore.withPermits(1)(task));
const results2 = yield* Effect.all(limited);

Resources

Feel free to explore the library for building robust, production‑grade TypeScript applications.

0 조회
Back to Blog

관련 글

더 보기 »

MCP의 일곱 대죄: 운영적 죄

운영상의 죄: 나태와 분노 이 죄들은 이 범주에 속하는데, 이는 라이브 MCP 시스템이 스트레스 하에서 어떻게 동작하는지를 결정하기 때문이다: 그것이 진실되게 실패하는지…