TL;DR

ジェネレータ関数を使って、async / await に近い書き方で Effect を組み立てる関数。

なぜ必要か

pipe で処理を組み立てると、ステップが増えるにつれて読みにくくなる。

const main = fetchRequest.pipe(
  Effect.filterOrFail(
    (response) => response.ok,
    (): FetchError => new FetchError(),
  ),
  Effect.flatMap(jsonResponse),
  Effect.catchTags({
    FetchError: () => Effect.succeed("Fetch error"),
    JsonError: () => Effect.succeed("Json error"),
  }),
)

Effect.gen を使うと、普段の TypeScript の構文に近い形で書ける。

const main = Effect.gen(function* () {
  const response = yield* fetchRequest
  if (!response.ok) return yield* new FetchError()
 
  return yield* jsonResponse(response)
})

仕組み

上のコードは、async / await のコードを次のように置き換えたものに近い。

  • async を Effect.gen にする
  • 無名関数をジェネレータ関数にする
  • await と throw を yield* にする
const main = async () => {
  const response = await fetchRequest()
  if (!response.ok) throw new FetchError()
 
  return await jsonResponse(response)
}

Effect.gen は、JavaScript のジェネレータとイテレータのプロトコルを組み合わせて、関数内の各ステップの成功やエラーを追跡している。

関連

出典