Effect-TS brings structured concurrency, typed errors, dependency injection, and resource management to TypeScript — all in one coherent system.
Core: The Effect Type
import { Effect, pipe } from 'effect';
// Effect<Success, Error, Requirements>
const program: Effect.Effect<string, Error, never> = pipe(
Effect.succeed(42),
Effect.map(n => n * 2),
Effect.flatMap(n =>
n > 50
? Effect.succeed(`Big number: ${n}`)
: Effect.fail(new Error('Too small'))
)
);
// Run it
Effect.runPromise(program).then(console.log);
Typed Errors (No More try/catch Guessing)
class NotFoundError { readonly _tag = 'NotFoundError'; }
class ValidationError { readonly _tag = 'ValidationError'; constructor(readonly message: string) {} }
const getUser = (id: number): Effect.Effect<User, NotFoundError | ValidationError> =>
pipe(
Effect.succeed(id),
Effect.flatMap(id =>
id < 0
? Effect.fail(new ValidationError('ID must be positive'))
: Effect.tryPromise({
try: () => db.findUser(id),
catch: () => new NotFoundError()
})
)
);
// Handle specific errors
const result = pipe(
getUser(42),
Effect.catchTag('NotFoundError', () => Effect.succeed(defaultUser)),
Effect.catchTag('ValidationError', (e) => Effect.die(e))
);
Concurrency
// Run 3 effects in parallel
const [users, posts, comments] = await Effect.runPromise(
Effect.all([fetchUsers, fetchPosts, fetchComments], { concurrency: 3 })
);
// Race — first to complete wins
const fastest = Effect.race(fetchFromCDN, fetchFromOrigin);
// Retry with backoff
const resilient = pipe(
fetchData,
Effect.retry({
times: 3,
schedule: Schedule.exponential('1 second')
})
);
Dependency Injection (Services)
class Database extends Context.Tag('Database')<Database, {
query: (sql: string) => Effect.Effect<Row[]>
}>() {}
const getUsers = pipe(
Database,
Effect.flatMap(db => db.query('SELECT * FROM users'))
);
// Provide implementation
const program = pipe(
getUsers,
Effect.provideService(Database, {
query: (sql) => Effect.tryPromise(() => pg.query(sql))
})
);
Why This Matters
- Typed errors: Know exactly what can fail at compile time
- Structured concurrency: No dangling promises or race conditions
- Dependency injection: Test anything by swapping implementations
- Resource safety: Automatic cleanup with Scope
Need custom TypeScript tooling or robust backend architecture? I build developer tools. Check out my web scraping actors on Apify or reach out at spinov001@gmail.com for custom solutions.
Top comments (0)