Blog Post

How to Effect TS? Learnings from reading the Effect Documentation

What I learned reading the Effect.website Documentation and attending the Effect Days Conference.

Why Effect? Michael Arnaldi, Effect Founder, summarized it best in this talk. It’s a great watch!

Though only watch it and only read on if you do care about production software. If you care about the craft of programming.

Effect focuses on handling errors, providing insight into your application, testing nicely and being able to maintain and scale the codebase.

How to effect - a set of learnings from reading effect docs.

I read through the Getting Started, Error Management, Resource Management and Requirement Management sections. Here’s all the notes on Effect best practices I picked up with some additions from the Effect Days Conference and workshop

  • Use namespace imports & import a as effect from “effect/Effect” for optimal tree shaking support. Mostly required in libraries!

  • Use functions over methods as they are tree shakeable & can easily be extended

    • -> cleaner more modular code & better compatibility with other libraries and modules
    • -> better view of tree shakability eliminates unused code
  • Effect is an immutable description of a workflow or operation that is lazily executed

    • -> creating an Effect does not immediatly execute it
  • Effects are not actually functions. They can model asynchronous, synchronous, concurrent and resourceful computations. They model or describe effectful interactions.

    • -> Execution via Effect Runtime System which interprets into actual interactions with the external world. Execution usually begins in single entry point e.g. main function.
  • Don’t throw errors! Use Effect.fail() for errors & Effect.succeed to return/succeed

    • -> explicit success & failure handling “leveraging the type system to track errors”
  • Handle Errors with Effect.catchAll / Effect.catchTag & other expected Error handlers

    • errors: Effect.fail(new Error(“We don’t lie”))
    • example tagged error: use dots -> Effect.catchTag + you can use complex objects via Tagged Errors
    • -> use tagged Errors
  • Effect docs for defect (unexpected error) handling! see effect.website

  • Interact with JavaScript/TypeScript (non effect code) via Effect.sync, Effect.try + Effect.promise, Effect.tryPromise

    • -> get the goodies from effect + you can add custom error handling while using libraries/gradually adopting effect.
  • You can use Effect.async for callback based APIs, you’ll manually type annotate here! Call resume only once!!!

    • -> you can add a custom clean-up function in case of interrupts that then gets executed
    • -> you can add AbortSignal support yourself :)
  • In Creating Effects read about guaranteeing fresh execution on each invocation with Effect.suspend

  • Unless you need a Promise or synchronous operation use Effect.runFork as default to run Effects

  • People writing effect code love generators. The “pure” functionalists will build pipelines. Generators good :)

    • -> Generators make your Effect code behave, feel like traditional synchronous code enhancing readability & error management
    • -> requires TypeScript target of “es2015” or higher
  • Building Pipelines: pipe() allows composing functions in a readable, sequential manner

    • It takes output of one function and passes it as the input to the next function in the pipeline
    • read: effect.website
  • Rule of Thumb on pipe() vs Effect.fn/Effect.gen:

    • Pipe for one-way data manipulation
    • Generators for business logic with conditionals
    • Thanks Rafi!
  • You want to use Custom Errors so you have a _tag on the error which overall is great for detailed error handling at compile/lint time via Tags and runtime via _tag.

  • When Tagging Services use the path e.g. /src/services/…/code.ts ->/src/services/…/code as Tag to make it for sure unique & help you always find the file too

    • Which makes the convention : <package.name>/<path>/<serviceName>
    • so the Anthropic Client of @effect/ai-anthropic package living in src/AnthropicClient.ts becomes Context.Tag("@effect/ai-anthropic/AnthropicClient")
  • Use Services? How can typesafely prototype by “just” defining the interfaces aka bring business requirements into code requirements and code it all up.

  • Only at the end you need to worry about how it is implemented or when you Dependency Inject (provide) the implementation to the Service.

    • -> provideService & provideServiceEffect are useful to have different implementations in different parts of the code, though generally you want to use Layers
    • -> Make sure to compose Layers and Effect.provide them only once
    • -> Recall from Tim’s Talk - you can have optional dependencies too!
  • To share schemas having a separate Schema package that is thus consumed in back-/frontend is recommended

  • Wrapping Promise Based Libraries into Effectful code is easy with a Service + use() function - see Effect Days 2025 workshop demo with OpenAI being wrapped


The end

To learn more about Effect and Effect Days + the Workshop read the full blog post

Copyright © HUPF Media All rights reserved.Terms of Use & Privacy Policy