DEV Community

Alex Spinov
Alex Spinov

Posted on

Effect Has a Free TypeScript Library — The Missing Standard Library for TS

TypeScript Has No Standard Library

Python has os, json, datetime, collections, itertools. Go has net/http, encoding/json, fmt.

TypeScript has... npm. Want retries? Install a package. Want schema validation? Another package. Want proper error handling? Another package. Want concurrency control? Another package.

Effect: A Standard Library for TypeScript

Effect is a comprehensive TypeScript library that handles errors, concurrency, retries, streaming, dependency injection, and more — with full type safety.

Error Handling That Actually Works

In regular TypeScript, errors are invisible:

// What can go wrong? TypeScript has no idea.
async function getUser(id: string): Promise<User> {
  const res = await fetch(`/api/users/${id}`)  // NetworkError?
  const data = await res.json()                // ParseError?
  return UserSchema.parse(data)                // ValidationError?
}
Enter fullscreen mode Exit fullscreen mode

With Effect, errors are part of the type:

import { Effect } from 'effect'

const getUser = (id: string): Effect.Effect<
  User,                          // Success type
  NetworkError | ParseError,     // Error types (VISIBLE!)
  HttpClient                     // Dependencies needed
> => ...

// TypeScript FORCES you to handle errors
const result = getUser('123').pipe(
  Effect.catchTag('NetworkError', () => fallbackUser),
  Effect.catchTag('ParseError', () => Effect.fail(new AppError()))
)
Enter fullscreen mode Exit fullscreen mode

Built-in Retries

import { Effect, Schedule } from 'effect'

const fetchWithRetry = fetchData.pipe(
  Effect.retry(
    Schedule.exponential('1 second').pipe(
      Schedule.compose(Schedule.recurs(3))
    )
  )
)
// Retries 3 times with exponential backoff. Type-safe. No library.
Enter fullscreen mode Exit fullscreen mode

Concurrency Control

// Process 100 items, max 10 at a time
const results = Effect.forEach(
  items,
  (item) => processItem(item),
  { concurrency: 10 }
)
Enter fullscreen mode Exit fullscreen mode

Dependency Injection

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

class Database extends Context.Tag('Database')<
  Database,
  { query: (sql: string) => Effect.Effect<Row[]> }
>() {}

// Your code declares what it needs
const getUsers = Database.pipe(
  Effect.flatMap(db => db.query('SELECT * FROM users'))
)

// Tests provide a mock
const testLayer = Layer.succeed(Database, {
  query: () => Effect.succeed([{ id: 1, name: 'Test' }])
})

// Production provides the real thing
const prodLayer = Layer.succeed(Database, {
  query: (sql) => pgPool.query(sql)
})
Enter fullscreen mode Exit fullscreen mode

When to Use Effect

  • Complex business logic with many failure modes
  • Data pipelines with retries, timeouts, and concurrency
  • Backend services that need structured error handling
  • Teams that want fewer runtime surprises

When It Is Overkill

  • Simple CRUD apps
  • Frontend components
  • Scripts and one-off tasks
  • Teams new to functional programming concepts

Get Started

npm install effect
Enter fullscreen mode Exit fullscreen mode

Building data pipelines? 88+ production scrapers on Apify handle retries, rate limits, and anti-bot for you. Custom solutions: spinov001@gmail.com

Top comments (0)