Using Context and Layers for Managing Services in Effect TypeScript

does a pattern like this makes sense:
import { Effect, Context, Layer } from "effect";

type ServiceConfig = Map<string, ServiceImpl>;

type ServiceImpl = {
  name: string;
  // ... other fields
};

// Single tag for the collection
const Services = Context.GenericTag<ServiceConfig>("Services");

const make = () => {
  const emptyServices = new Map<string, ServiceImpl>();
  return Context.make(Services, emptyServices);
};

const addService =
  (config: ServiceImpl) => (ctx: Context.Context<ServiceConfig>) => {
    const services = Context.get(ctx, Services);
    const newServices = new Map(services);
    newServices.set(config.name, config);
    return Context.make(Services, newServices);
  };

const toLayer = (ctx: Context.Context<ServiceConfig>) =>
  Layer.succeed(Services, Context.get(ctx, Services));

const ctx = make().pipe(
  addService({ name: "service-a" }),
  addService({ name: "service-b" }),
  addService({ name: "service-c" }),
);

const program = Effect.gen(function*() {
  const services = yield* Services;

  // const core = services.get("service-a");
  // or iterate
  for (const [name, config] of services) {
    console.log(name, config);
  }
});

const ServicesLive = toLayer(ctx);

program.pipe(Effect.provide(ServicesLive), Effect.runPromise);


Feel like it could be done with Layers as well in a better way, but not sure how.
Was this page helpful?