Upgrade to Pro — share decks privately, control downloads, hide ads and more …

これって Effect でできたのでは? / TSKaigi Mashup Kansai #2

Avatar for Susisu Susisu
July 24, 2026

これって Effect でできたのでは? / TSKaigi Mashup Kansai #2

Avatar for Susisu

Susisu

July 24, 2026

More Decks by Susisu

Other Decks in Programming

Transcript

  1. 我々はどうすべきか • (特にサーバーサイド TypeScript について) • Hono, Next.js などが全てをカバーしてくれるわけではない •

    NestJS というかデコレータは先行き怪しい ff ff • E ect やっていき / E ect やめていき
  2. E ect • https://e ect.website • E ect-TS とも ff

    ff ff • TypeScript の汎用ライブラリ/フレームワーク
  3. 例外処理 • E ect では Effect<A, E> を使ってプログラムを表現する • c.f.

    Promise<A>, Result<A, E> import { Effect } from "effect" ff const divide = ( a: number, b: number ): Effect.Effect<number, "DIVIDE_BY_ZERO"> => b === 0 ? Effect.fail("DIVIDE_BY_ZERO") : Effect.succeed(a / b)
  4. 例外処理 import { Console, Effect } from "effect" // main:

    Effect.Effect<void, "DIVIDE_BY_ZERO"> const main = Effect.gen(function* () { const answer = yield* divide(42, 7) yield* Console.log(answer) }) Effect.runFork(main) // => 6
  5. 例外処理 import { Console, Effect, Either } from "effect" //

    main: Effect.Effect<void, never> const main = Effect.gen(function*() { const answer = yield* divide(42, 7).pipe(Effect.either) if (Either.isLeft(answer)) return yield* Console.log(answer.right) }); Effect.runFork(main) // => 6
  6. DI • E ect では Effect<A, E, R> を使ってプログラムを表現する ff

    • R はプログラムの実行に必要な依存関係 (requirements)
  7. DI import { Console, Context, Effect } from "effect" class

    Random extends Context.Tag("MyRandomService")< Random, { readonly next: Effect.Effect<number> } >() {} // program: Effect.Effect<void, never, Random> const program = Effect.gen(function* () { const random = yield* Random const randomNumber = yield* random.next yield* Console.log(`random number: ${randomNumber}`) }) Effect.runFork(program) // ← 型エラー
  8. DI // ... const runnable = Effect.provideService(program, Random, { next:

    Effect.sync(() => Math.random()) }) Effect.runFork(runnable) // => 0.6792671590288922
  9. 並行処理 • Effect<A, E, R> は Fiber 上で実行される • 軽量スレッド,

    Go でいうところの goroutine import { Effect, Fiber } from "effect" const main = Effect.gen(function* () { const fiber = yield* Effect.fork(child) // ... yield* Fiber.join(fiber) })
  10. 並行処理 • Fiber は中断可能 • Go では context.WithCancel を使ってやるようなやつ import

    { Effect, Fiber } from "effect" const main = Effect.gen(function* () { const fiber = yield* Effect.fork(child) yield* Effect.sleep("10 seconds") const exit = yield* Fiber.interrupt(fiber) });
  11. 並行処理 • 並行処理で使える Queue なども揃ってる • Go でいう channel など

    import { Console, Effect, Fiber, Queue } from "effect" const main = Effect.gen(function* () { const queue = yield* Queue.bounded<number>(1) const fiber = yield* Effect.fork(Queue.take(queue).pipe(Effect.andThen(Console.log))) yield* Queue.offer(queue, 42) yield* Fiber.join(fiber) })
  12. デメリット • pipe / ジェネレータを使った記法はややゴツく見えるかも • 外の世界のライブラリを使う場合は I/F を整える必要がある •

    先述の通りあらかじめ用意されているものも多い • めちゃめちゃ機能が多い • ライブラリを探すのと同じように必要な機能だけ見れば良くはある
  13. 余談 • fp-ts との関係と違い • Scala の ZIO との関係 •

    Effect<A, E, R> を「エフェクト」と呼んでいいのか