TL;DR

Effect で、Service を作る処理を抽象化したもの。Service 間の依存関係を管理する。

なぜ必要か

Service はほかの Service に依存することがある。依存を Service のインタフェースに出すと、たとえば query の型が Config | Logger を要求するようになり、テストが難しくなる。Layer は Service を作るときに依存を解決するので、Service のインタフェースをきれいに保てる。公式ドキュメントは、Layer を「Service を作るためのコンストラクタ」と説明している。

仕組み

型は Layer<RequirementsOut, Error, RequirementsIn> で、それぞれ作る Service、作るときに起こりうるエラー、作るのに必要な依存を表す。

  • Layer.succeed: 依存のない値から Layer を作る
  • Layer.effect: ほかの Service を取り出しながら Layer を作る
  • Layer.merge: Layer を並べて合成する
  • Layer.provide: ある Layer の出力を、別の Layer の依存に渡す

最後に Effect.provide で Layer をプログラムに渡す。要求する依存が never になれば、プログラムを実行できる。

例

const LoggerLive = Layer.effect(
  Logger,
  Effect.gen(function* () {
    const config = yield* Config
    return {
      log: (message) =>
        Effect.gen(function* () {
          const { logLevel } = yield* config.getConfig
          console.log(`[${logLevel}] ${message}`)
        }),
    }
  }),
)

LoggerLive の型は Layer<Logger, never, Config> で、Config に依存して Logger を作る。

関連

出典