Effect-TSは『try-catchの限界』を超えるアプローチ
Effect-TSはScala ZIOやCats Effectの設計思想をTypeScriptに移植したライブラリで、エラー・依存性・非同期処理を1つのEffect<A, E, R>型で表現します。Aは成功値、Eはエラー型、Rは依存関係。すべてが型として可視化されるため、業務ロジックの複雑性に押し負けやすい大規模TSアプリで威力を発揮します。Discord・Vercel・Scale AIなどでの本番採用例が公開されています。
Effect-TS採用を検討すべき5つのシグナル
- try-catchが入れ子になり、エラーが本当にハンドリングされているか追えなくなった
- Promise.allSettledの結果型ハンドリングで毎回ボイラープレートを書いている
- 依存性注入(DI)のためにNestJSの仕組みやInversifyJSを使っているが重い
- リトライ・タイムアウト・サーキットブレーカを毎回独自実装している
- 業務ロジックの単体テストがモック地獄になっている
従来のTSコードとの実務比較
従来のPromise/async-await: 簡潔だがエラー型はunknown。失敗ケースが追えない。
neverthrow/ts-results: Result型でエラーを型化できるが、依存性注入や非同期合成は別途設計が必要。
Effect-TS: エラー・依存性・並行性・リソース管理を1つのEffect型で完結。学習コストは高いが、複雑業務での恩恵が大きい。
Effect-TS実装の基本パターン
(1) Effect構築: Effect.succeed(value)・Effect.fail(error)・Effect.tryPromise()
(2) 合成: Effect.gen(function*(){ yield* op1; yield* op2 })でジェネレータ風に書ける
(3) エラー処理: Effect.catchTag('NetworkError', handler)で型安全にタグ別ハンドリング
(4) 依存性注入: Effect.provideService(Logger, instance)でレイヤとして注入
(5) 並行制御: Effect.all([op1, op2], { concurrency: 5 })で並列度を宣言的に制御
本番採用の判断基準
(1) チームの関数型素養: Scala/Haskell/F#経験者がいるとスムーズ。完全未経験チームはハードルあり
(2) 業務ロジック複雑度: 単純なCRUDなら過剰投資。マルチステップビジネスフローでは強力
(3) 長期保守性: 5年以上保守する基盤コードに導入する価値が大きい
(4) パフォーマンス: 軽量ランタイムだがオーバーヘッドあり。マイクロサービスのホットパスは要計測
(5) 段階導入: 新規モジュールだけ採用し既存はpromise系維持が現実的
実務で詰まる3つの落とし穴
- Effect.gen のジェネレータ構文: 慣れるまで読みづらい。チーム全員に勉強会が必要
- テスト設計: Layerでテスト用依存を差し替えるパターンを習得しないとモック地獄が再現
- エコシステム: 既存ライブラリ(Express等)とEffectを橋渡しするブリッジ実装が必要なケースが頻出
30日学習プラン
- 1週目: 公式チュートリアルでEffect/Layer/Schemaの基礎を理解
- 2週目: 既存のPromiseベースAPIをEffect化して書き直す
- 3週目: Schemaバリデーション・タグ別エラーハンドリングを実装
- 4週目: HTTPサーバ(@effect/platform)でAPIを書き、テスト・本番デプロイまで通す
関連リンク
TypeScriptの設計は TypeScript実践、関数型のキャリア論は 関数型プログラミングとキャリア、エラーハンドリング設計は エラーハンドリング実践 を参照してください。tRPCとの組み合わせは tRPC深掘り もどうぞ。