ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-04-29中級

Antigravity と Effect-TS で堅牢なエラーハンドリングを設計する実装ガイド

Effect-TS の Effect.gen と Layer を Antigravity の AI 補完で書きこなすための実装ガイド。型に乗ったエラーハンドリング設計を実コードで解説します。

antigravity435effect-tstypescript26error-handling2

try/catch で囲む箇所が増えるたびに、どのエラーが投げられるのか自信が持てなくなります。Node.js で TypeScript を書いている方なら、一度はこの感覚に出会ったのではないでしょうか。Effect-TS(@effect/io)は、その不安を型システムに肩代わりさせるためのライブラリです。

ただ、Effect-TS はジェネレータ構文と高機能な型推論を駆使するため、補完がほとんど効かないエディタで書こうとすると一気に厳しくなります。Antigravity の AI 補完は、Effect の REA パラメータを文脈から読み取ってくれるため、このライブラリと組み合わせると体験が一段変わります。

なぜ Antigravity は Effect-TS と相性がいいのか

Effect-TS のコアは Effect<Requirements, Error, Success> という三型パラメータの計算型です。async/await と違い、エラー型まで型に持ち上がるため、関数のシグネチャだけで「何が失敗しうるか」が読み取れます。

ただし、この恩恵を実装側で受け取るには、ジェネレータ内でエラーを正しく yield* _(...) する規律が必要です。Antigravity の AI 補完は、上記の三型パラメータを推論しつつ「次にどんなエラーが起こりうるか」を提示してくれるので、書きながら型を整えるサイクルが回しやすくなります。

私はこのとき、Antigravity のサイドバーに node_modules/@effect/io/dist/esm/index.d.ts を開きっぱなしにしておくと、AI が型情報を強く参照してくれることに気づきました。型定義ファイルを文脈に含めること、これが Effect-TS を Antigravity で書くときの最初のコツです。

TypeScript の strict 設定を Antigravity で運用するガイド と合わせると、補完精度がさらに伸びます。

最初の Effect.gen ブロックを書く

まずは、HTTP リクエストとデータベースアクセスを組み合わせる最小例です。Antigravity に「Effect.gen で書き直して」と指示すると、以下のような構造が返ってきます。

import { Effect } from "effect"
import { HttpClient } from "@effect/platform"
 
// fetchUserProfile: ユーザーIDを受け取り、API から取得して整形する
// 戻り型: Effect<HttpClient, FetchError | ParseError, UserProfile>
const fetchUserProfile = (userId: string) =>
  Effect.gen(function* (_) {
    const client = yield* _(HttpClient.HttpClient)
    const response = yield* _(
      client.get(`/api/users/${userId}`)
    )
    const json = yield* _(response.json)
    return parseUserProfile(json) // Schema でバリデート
  })
 
// 期待される実行結果(Layer 提供後):
// → 成功時: UserProfile オブジェクト
// → 失敗時: FetchError または ParseError が型で伝播

ここで重要なのは、Effect.gen の中ではエラーが投げられない点です。yield* _(...) で受け取った値は成功時の値だけで、エラーは型パラメータ E 側に積み上がります。fetchUserProfile を呼び出す側は、HttpClient を Layer で提供しないとコンパイルが通らないため、依存関係も型で表現される設計です。

ドメインエラーを共用体型で設計する

Effect-TS で陥りやすい罠は、エラーをすべて Error クラスでまとめてしまうパターンです。これでは型システムの恩恵が半減します。私は、ドメインごとに Data.TaggedError を使った判別共用体を作るやり方をおすすめします。

import { Data } from "effect"
 
// 各エラーは _tag フィールドで判別可能な共用体になる
class UserNotFound extends Data.TaggedError("UserNotFound")<{
  userId: string
}> {}
 
class RateLimitExceeded extends Data.TaggedError("RateLimitExceeded")<{
  retryAfter: number
}> {}
 
class ParseError extends Data.TaggedError("ParseError")<{
  reason: string
}> {}
 
type FetchUserError = UserNotFound | RateLimitExceeded | ParseError
 
// 期待動作: catchTag で個別ハンドリング後、E パラメータからその型が消える

この設計なら、Effect.catchTag("RateLimitExceeded", err => ...) のように特定エラーだけを受けて再試行する処理が、すべて型で守られます。catchTag で捕まえた後の Effect から、捕捉したエラー型が型レベルで消えるのも気持ちが良いところです。

AI エージェントの本番エラーハンドリング設計 でも触れたように、エラーは「種類で分類して、それぞれに専用の回復戦略を持つ」ことで運用が安定します。

Layer による依存注入で本番とテストを切り分ける

Effect-TS の Layer は、依存関係を構築する手順を値として表現する仕組みです。本番ではリアルな HTTP クライアントを、テストでは固定値を返すスタブを供給する、といった切替が型を壊さずにできます。

import { Layer, Effect } from "effect"
import { HttpClient } from "@effect/platform"
 
// 本番用: 実 HTTP クライアントを構築
const HttpClientLive = HttpClient.layer
 
// テスト用: 任意のレスポンスを返すスタブ
const HttpClientTest = Layer.succeed(
  HttpClient.HttpClient,
  HttpClient.makeWith({
    request: () => Effect.succeed(mockResponse),
  })
)
 
// 実行時に Layer を差し替えるだけで切替可能
const program = fetchUserProfile("u_123")
 
// 本番:
Effect.runPromise(program.pipe(Effect.provide(HttpClientLive)))
// → 実 API にリクエストし、UserProfile が返る
 
// テスト:
Effect.runPromise(program.pipe(Effect.provide(HttpClientTest)))
// → スタブから固定値が返り、外部依存なしで検証可能

Antigravity に「この program 用のテスト Layer を生成して」と頼むと、上記のスタブパターンを高い精度で書いてくれます。Layer の合成(Layer.mergeLayer.provideMerge)も、ライブラリの型定義をエディタが見ているおかげで補完が安定します。

Antigravity で Effect ジェネレータを書くコツ

実際に書き続けて気づいた、補完精度を上げる工夫を3つご紹介します。

第一に、ファイルの先頭で必要な import を全部書ききることです。EffectDataLayer などはモジュールパスが似ているため、後から AI に補完させると遠回りすることがあります。先に枠を作っておくと、関数本体の補完が早くなります。

第二に、戻り型コメントを関数定義の直前に書くことです。「// 戻り型: Effect<R, E, A>」という1行があるだけで、Antigravity の AI が Effect.gen 内のジェネレータをかなり精緻に補完してくれます。

第三に、yield* _(...) か新構文(_ を省略するスタイル)かをプロジェクト内で統一することです。混在していると AI が両方を提案して補完が乱れます。tsconfig の targetES2022 以上に上げ、どちらの構文を採用するかチームで決めておきましょう。

このあたりの周辺知識は、Zod を中心としたスキーマ駆動開発の記事 で扱った原則とも共通しています。型を最初に固める、というワークフロー設計は、Effect-TS でも Zod でも変わりません。

今日から始める一歩

新しいプロジェクトでいきなり Effect-TS を全面採用するのは、私の経験では負荷が大きすぎます。おすすめは、エラーハンドリングが特に複雑な1関数を選び、そこだけ Effect で書き直すことです。Antigravity に既存の関数を貼り付けて「Effect.gen で書き直し、エラーを TaggedError で表現してください」と頼むと、十分な雛形が生成されます。

そこから1日1関数のペースで広げていくと、2週間ほどで主要な API ハンドラがすべて型で守られた状態になります。手元のプロジェクトで「最も try/catch がネストしている関数」を1つ選ぶところから始めてみてはいかがでしょうか。

書籍で体系的に

シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

アプリ開発2026-05-03
Antigravity × TypeScript で作る冪等性キーと重複排除ストア本番設計ガイド
Stripe Webhook の二重課金や Temporal ワークフローの再実行で起きる重複処理を、冪等性キーと重複排除ストアで止める本番設計を、Antigravity を伴走者にして TypeScript で組み上げる実践ガイドです。
アプリ開発2026-05-01
Antigravity で React Server Components の境界を整理する — Next.js 16 で迷わなくなるワークフロー
Server / Client の境界判断は Next.js 16 で最も詰まりやすいポイントです。Antigravity を境界設計のレビュアーとして使い、`use client` の貼り間違いとシリアライズエラーをゼロに近づける個人開発の実践ワークフローを共有します。
アプリ開発2026-04-30
Antigravity × Better Auth でモダンTypeScript認証基盤を構築する
NextAuth疲れに終止符を打つBetter AuthをAntigravityで導入する実践ガイド。スキーマ自動生成・OAuth・RBAC・Passkeyまで本番運用パターンを網羅します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →