Effect is a TypeScript library for building complex, reliable applications. It brings typed errors, dependency injection, concurrency, and observability — all type-safe.
Quick Start
npm install effect
Why Effect?
Regular TypeScript:
// What can go wrong? What does this need? No idea from the type.
async function getUser(id: string): Promise<User> { ... }
With Effect:
// Types tell you: can fail with NotFound or DbError, needs DbClient
function getUser(id: string): Effect<User, NotFound | DbError, DbClient> { ... }
Basic Usage
import { Effect, pipe } from 'effect'
const program = pipe(
Effect.succeed(42),
Effect.map(n => n * 2),
Effect.tap(n => Effect.log(\`Result: \${n}\`))
)
Effect.runPromise(program) // logs "Result: 84"
Typed Errors
class NotFound { readonly _tag = 'NotFound' }
class DbError { readonly _tag = 'DbError' }
const getUser = (id: string): Effect.Effect<User, NotFound | DbError> =>
pipe(
queryDb(id),
Effect.catchTag('DbError', () => Effect.fail(new NotFound()))
)
// TypeScript knows EXACTLY which errors can occur
Dependency Injection (Services)
class DbClient extends Context.Tag('DbClient')<DbClient, { query: (sql: string) => Effect.Effect<any[]> }>() {}
const program = pipe(
DbClient,
Effect.flatMap(db => db.query('SELECT * FROM users'))
)
// Provide the implementation at the edge
const runnable = program.pipe(
Effect.provideService(DbClient, { query: realDbQuery })
)
Concurrency
// Run 3 effects concurrently, collect results
const results = Effect.all([fetchUsers, fetchPosts, fetchComments], { concurrency: 3 })
// Race — first to complete wins
const fastest = Effect.race(fetchFromCacheEffect, fetchFromDbEffect)
The Bottom Line
Effect is for TypeScript what ZIO is for Scala. If you build complex backend systems and want typed errors, DI, and concurrency — Effect is the most complete solution in the TS ecosystem.
Need to automate data collection or build custom scrapers? Check out my Apify actors for ready-made tools, or email spinov001@gmail.com for custom solutions.
Top comments (0)