Using Context and Layers for Managing Services in Effect TypeScript
does a pattern like this makes sense:
Feel like it could be done with Layers as well in a better way, but not sure how.
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);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.
