Define layers inside Context.Tag

We saw how convenient it is to use class and Context.tag. Since we are working with a class we are able to define additional methods and attributes directly inside it.

With this pattern we have all services implementations defined as separate static parameters:

export class PokeApi extends Context.Tag("PokeApi")<
  PokeApi,
  Effect.Effect.Success<typeof make>
>() {
  static readonly Live = Layer.effect(this, make).pipe(
    Layer.provide(Layer.mergeAll(PokemonCollection.Live, BuildPokeApiUrl.Live))
  );

  static readonly Mock = Layer.succeed(
    this,
    PokeApi.of({
      getPokemon: Effect.succeed({
        id: 1,
        height: 10,
        weight: 10,
        name: "my-name",
        order: 1,
      }),
    })
  );
}

Swapping layers for testing, mocking, development, and production becomes a (less than) 1 line change:

const MainLayer = Layer.mergeAll(
  PokeApi.Mock,
);

Furthermore, we can access all layers, methods, and even helper functions inside the same class with a single import:

import { Effect, Layer } from "effect";
// 👇 Single import for all layers, methods, and helper functions (`Live`, `Mock`, etc.)
import { PokeApi } from "./PokeApi";

const MainLayer = Layer.mergeAll(
  PokeApi.Mock,
);

This pattern is common in effect and used also for internal modules.