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>
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 }) });
});
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)));
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"),
);
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));
Getting Started
npm install effect
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)