DEV Community

Alex Spinov
Alex Spinov

Posted on

Effect Has a Free API You Should Know About

Effect is a powerful TypeScript library for building robust, type-safe applications. Its API for error handling, concurrency, and dependency injection is unlike anything else in the JS ecosystem.

Effect — Type-Safe Error Handling

Effect tracks errors in the type system:

import { Effect, pipe } from "effect"

class NetworkError {
  readonly _tag = "NetworkError"
  constructor(readonly message: string) {}
}

class ParseError {
  readonly _tag = "ParseError"
  constructor(readonly input: string) {}
}

// Effect<User, NetworkError | ParseError, never>
const fetchUser = (id: string) =>
  pipe(
    Effect.tryPromise({
      try: () => fetch(`/api/users/${id}`).then(r => r.json()),
      catch: (e) => new NetworkError(String(e))
    }),
    Effect.flatMap((data) =>
      typeof data.name === "string"
        ? Effect.succeed(data as User)
        : Effect.fail(new ParseError(JSON.stringify(data)))
    )
  )

// Handle specific errors
const program = pipe(
  fetchUser("123"),
  Effect.catchTag("NetworkError", (e) =>
    Effect.succeed({ name: "Offline User", cached: true })
  )
)
Enter fullscreen mode Exit fullscreen mode

Concurrency with Fibers

Effect provides structured concurrency:

import { Effect, Fiber } from "effect"

// Run tasks in parallel with limit
const fetchAllUsers = (ids: string[]) =>
  Effect.forEach(ids, fetchUser, { concurrency: 5 })

// Race — first to complete wins
const fastest = Effect.race(fetchFromCache, fetchFromDB)

// Timeout
const withTimeout = pipe(
  fetchUser("123"),
  Effect.timeout("5 seconds")
)

// Background fiber
const program = Effect.gen(function* () {
  const fiber = yield* Effect.fork(longRunningTask)
  yield* doOtherWork()
  const result = yield* Fiber.join(fiber)
  return result
})
Enter fullscreen mode Exit fullscreen mode

Dependency Injection with Services

Effect has built-in DI — no frameworks needed:

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

// Define service interface
class Database extends Context.Tag("Database")<
  Database,
  {
    readonly query: (sql: string) => Effect.Effect<any[]>
    readonly insert: (table: string, data: any) => Effect.Effect<void>
  }
>() {}

// Use service in program
const getUsers = Effect.gen(function* () {
  const db = yield* Database
  return yield* db.query("SELECT * FROM users")
})

// Provide implementation
const PostgresLayer = Layer.succeed(Database, {
  query: (sql) => Effect.tryPromise(() => pg.query(sql).then(r => r.rows)),
  insert: (table, data) => Effect.tryPromise(() => pg.insert(table, data))
})

// Run with real DB
const result = pipe(
  getUsers,
  Effect.provide(PostgresLayer),
  Effect.runPromise
)
Enter fullscreen mode Exit fullscreen mode

Schema — Runtime Validation

import { Schema } from "effect"

const User = Schema.Struct({
  id: Schema.Number,
  name: Schema.String.pipe(Schema.minLength(2)),
  email: Schema.String.pipe(Schema.pattern(/@/)),
  role: Schema.Literal("admin", "user", "editor")
})

type User = Schema.Schema.Type<typeof User>

// Parse with Effect error channel
const parseUser = Schema.decodeUnknown(User)
const result = parseUser({ id: 1, name: "A", email: "bad", role: "admin" })
// Effect<User, ParseError>
Enter fullscreen mode Exit fullscreen mode

Streams — Reactive Data Processing

import { Stream, Effect } from "effect"

const processLogs = pipe(
  Stream.fromAsyncIterable(readLogFile(), () => new Error("read failed")),
  Stream.filter((line) => line.includes("ERROR")),
  Stream.map((line) => parseLogLine(line)),
  Stream.grouped(100), // Batch every 100
  Stream.mapEffect((batch) => sendToElastic(batch), { concurrency: 3 }),
  Stream.runDrain
)
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • Type-safe errors — errors tracked in the type system
  • Structured concurrency with fibers, races, timeouts
  • Dependency injection without frameworks
  • Schema for runtime validation with type inference
  • Streams for reactive data processing
  • Retry, scheduling, metrics built-in

Explore Effect docs for the complete API.


Building web scrapers or data pipelines? Check out my Apify actors for ready-made solutions, or email spinov001@gmail.com for custom development.

Top comments (0)