Dependency management with types

If you inspect the type of program now you can notice a third type parameter inside Effect:

Every Effect has 3 type parameters: success, errors, and dependencies. Our program has a dependency on the PokeApi service
Every Effect has 3 type parameters: success, errors, and dependencies. Our program has a dependency on the PokeApi service

Since now we ignored the third type parameter, as it was always never (no dependencies).

As we start to compose services together this third parameter will collect a union of all the dependencies required to run the program.

The best part (again) is type-safety. All dependencies are declared on the Effect type. This makes sure that we get a compile-time error if we forget to provide a dependency when running the final program.

We get a type error if we try to execute runPromise on program:

import { Effect } from "effect";
import { PokeApi } from "./PokeApi";

const program = Effect.gen(function* () {
  const pokeApi = yield* PokeApi;
  return yield* pokeApi.getPokemon;
});

///               👇 Error here
Effect.runPromise(program).then(console.log);
Type 'PokeApi' is not assignable to type 'never'.

That's because every run method in effect requires the third type parameter to be never, meaning that all the dependencies have been provided.

Effect.ts
export const runPromise: <A, E>(
  effect: Effect<A, E, never>,
  options?: { readonly signal?: AbortSignal } | undefined
) => Promise<A> = _runtime.unsafeRunPromiseEffect

How do we provide a dependency? That's the next step!