Layerを使って実体を流し込む流れ
登場人物
Serviceの
Interface
識別子
②実体
③Layer
①と②のペア
④program
Serviceのinterface(①)のみに依存したもの
具体的な②のことは知らない
⑤runnable
③と④を結びつけたもの
実行できる
そのため、Layerの長所の一部のみにしか使ってない
code:ts
import { Effect, Layer } from "effect"
classでも関数でも書ける
code:ts
// ①
class Random extends Context.Tag("MyRandomService")<
Random,
{
readonly next: Effect.Effect<number>;
}
() {}
// ①
type Log = (message: string) => Effect.Effect<void>;
const Logger = Context.GenericTag<Log>("MyLoggerService");
② Serviceの具体的な実装・実体
code:ts
// ② Serviceの具体的な実装・実体
const next = Effect.sync(() => Math.random());
const log: Log = (message: string) => Effect.sync(() => console.log(message));
例えば、実装用とテスト用、とか
例えば、Node用、Bun用、とか
④ program
具体的な②のことは知らない
code:ts
// ④ program
const program = Effect.gen(function* () {
const random = yield* Random
const logger = yield* Logger
const randomNumber = yield* random.next
return yield* logger.log(String(randomNumber))
})
型に全てのcontextが乗る
①に②を使って結びつける宣言
code:ts
// ③
const RandomLive = Layer.succeed(Random, { next });
const LoggerLive = Layer.succeed(Logger, log);
必要であれば、Layer同士の結合もすれば良い
code:ts
// ③+③
const AppConfigLive = Layer.merge(RandomLive, LoggerLive)
あえて密結合にするという選択をすることになる
⑤runnable
構築した④programに、③Contextを結びつけて、実体を流し込む
code:ts
// ⑤ runnable
const runnable = Effect.provide(program, AppConfigLive)