DEV Community

Alex Spinov
Alex Spinov

Posted on

Effect-TS Has a Free API You're Not Using

Effect is a TypeScript library for building production-grade applications with structured concurrency, dependency injection, and error handling built in. Think of it as Go's error handling + Rust's Result type + Java's Spring DI — for TypeScript.

The Free APIs You're Missing

1. Effect.gen — Async/Await on Steroids

import { Effect, pipe } from "effect";

const program = Effect.gen(function* () {
  const user = yield* fetchUser("user-123");
  const posts = yield* fetchPosts(user.id);
  const enriched = yield* enrichWithMetrics(posts);
  return { user, posts: enriched };
});

// Every yield* can fail — and the error type is tracked!
// program: Effect<Result, UserNotFound | PostsError | MetricsError, UserService | PostService>
Enter fullscreen mode Exit fullscreen mode

2. Typed Errors — Errors in the Type System

class UserNotFound extends Data.TaggedError("UserNotFound")<{ id: string }> {}
class NetworkError extends Data.TaggedError("NetworkError")<{ cause: unknown }> {}

const getUser = (id: string): Effect.Effect<User, UserNotFound | NetworkError> =>
  Effect.gen(function* () {
    const response = yield* Effect.tryPromise({
      try: () => fetch(`/api/users/${id}`),
      catch: (e) => new NetworkError({ cause: e }),
    });
    if (!response.ok) yield* Effect.fail(new UserNotFound({ id }));
    return yield* Effect.tryPromise({ try: () => response.json(), catch: (e) => new NetworkError({ cause: e }) });
  });
Enter fullscreen mode Exit fullscreen mode

3. Layer — Dependency Injection

class Database extends Context.Tag("Database")<Database, { query: (sql: string) => Effect.Effect<any[]> }>() {}
class Logger extends Context.Tag("Logger")<Logger, { log: (msg: string) => Effect.Effect<void> }>() {}

const DatabaseLive = Layer.succeed(Database, {
  query: (sql) => Effect.tryPromise(() => pg.query(sql).then(r => r.rows)),
});

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

const AppLayer = Layer.mergeAll(DatabaseLive, LoggerLive);

// Run with dependencies
Effect.runPromise(pipe(program, Effect.provide(AppLayer)));
Enter fullscreen mode Exit fullscreen mode

4. Schedule — Retry and Repeat Policies

import { Schedule } from "effect";

const retryPolicy = Schedule.exponential("100 millis").pipe(
  Schedule.compose(Schedule.recurs(5)),
  Schedule.jittered,
);

const resilientFetch = pipe(
  fetchData,
  Effect.retry(retryPolicy),
  Effect.timeout("30 seconds"),
);
Enter fullscreen mode Exit fullscreen mode

5. Stream — Reactive Data Processing

import { Stream } from "effect";

const processLargeFile = Stream.fromReadableStream(
  () => fetch("/api/data").then(r => r.body!),
  (e) => new StreamError({ cause: e })
).pipe(
  Stream.decodeText(),
  Stream.splitLines,
  Stream.map(JSON.parse),
  Stream.filter((row) => row.status === "active"),
  Stream.mapEffect((row) => enrichRow(row)),
  Stream.grouped(100),
  Stream.mapEffect((batch) => insertBatch(batch)),
);

Effect.runPromise(Stream.runDrain(processLargeFile));
Enter fullscreen mode Exit fullscreen mode

Getting Started

npm install effect
Enter fullscreen mode Exit fullscreen mode

Need data from any website delivered as clean JSON? I build production web scrapers that handle anti-bot, proxies, and rate limits. 77 scrapers running in production. Email me: Spinov001@gmail.com

Check out my awesome-web-scraping list for the best scraping tools and resources.

Top comments (0)