// Implementation of part of a service
const myFunction = Effect.fn("myFunction")(function*(params: MyParams){
const myDependency1 = yield* MyDependency1;
const myDependency2 = yield* MyDependency2;
return [myDependency1, myDependency2, params] // <-- do things.
});
// Now I want to expose my service implementation as a service.
// The pain already starts here, because I have to type out `myFunction`s
// signature, even though I could derive it from `myFunction` if it
// wasn't for the baked-in dependencies it has.
export type MyServiceInterface = {
myFunction: (params: MyParams) => Effect.Effect<
MyFunctionResult,
MyFunctionError,
never // <-- crucially, the "dependency leak" has been removed
>
}
// Boilerplate follows:
// I have to manually hoist every function's dependencies out to the service acquiring Effect.
// yikes
type MyFunctionDependencies = Effect.Effect.Context<ReturnType<typeof myFunction>>;
const acquireMyService = Effect.gen(function*(){
// eye roll
const myFunctionDeps = yield* Effect.context<MyFunctionDependencies>();
return {
// cringe
myFunction: (params: MyParams) => myFunction(params).pipe(Effect.provide(myFunctionDeps))
}
});
// Desired result:
export class MyService extends Context.Tag("MyService")<MyService, MyServiceInterface>() {
static readonly Live = Layer.effect(this, acquireMyService);
}
// Implementation of part of a service
const myFunction = Effect.fn("myFunction")(function*(params: MyParams){
const myDependency1 = yield* MyDependency1;
const myDependency2 = yield* MyDependency2;
return [myDependency1, myDependency2, params] // <-- do things.
});
// Now I want to expose my service implementation as a service.
// The pain already starts here, because I have to type out `myFunction`s
// signature, even though I could derive it from `myFunction` if it
// wasn't for the baked-in dependencies it has.
export type MyServiceInterface = {
myFunction: (params: MyParams) => Effect.Effect<
MyFunctionResult,
MyFunctionError,
never // <-- crucially, the "dependency leak" has been removed
>
}
// Boilerplate follows:
// I have to manually hoist every function's dependencies out to the service acquiring Effect.
// yikes
type MyFunctionDependencies = Effect.Effect.Context<ReturnType<typeof myFunction>>;
const acquireMyService = Effect.gen(function*(){
// eye roll
const myFunctionDeps = yield* Effect.context<MyFunctionDependencies>();
return {
// cringe
myFunction: (params: MyParams) => myFunction(params).pipe(Effect.provide(myFunctionDeps))
}
});
// Desired result:
export class MyService extends Context.Tag("MyService")<MyService, MyServiceInterface>() {
static readonly Live = Layer.effect(this, acquireMyService);
}