mcpField
N
neverthrow-wrap-exceptions

neverthrow-wrap-exceptions

github.com/code-sherpas開発045 回インストール1 日前に更新
リポジトリ

neverthrow-wrap-exceptions について

neverthrow-wrap-exceptionsは、回復可能な同期・非同期例外を型付きのneverthrow結果に変換するコーディングスキルです。適切なラッパーの選択と、明示的なエラーマッピングを支援します。

主な機能

  1. 01失敗の形に応じたラッパー選択
  2. 02エラーの明示的な型変換
  3. 03既存のResult値の合成
  4. 04変換目的だけのcatchチェーンの置き換え
  5. 05例外処理の変更内容の検証

活用シーン

  1. 01例外を投げる同期パーサーのラップ
  2. 02拒否されたPromiseをドメインエラーに変換
  3. 03catchによる場当たり的な変換のリファクタリング
  4. 04編集したコードのエラー処理を確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/code-sherpas/agent-skills --skill neverthrow-wrap-exceptions

インストール後、Claude Code で/neverthrow-wrap-exceptionsを入力して読み込まれたか確認します。

詳細

Neverthrow による例外のラップ

目標

場当たり的な try/catch ではなく、neverthrow のヘルパーを使って回復可能な例外を捕捉します。

このスキルが対象とするのは例外の捕捉のみです。タスクで公開戻り値のシグネチャも変更する場合は、このスキルと併せて neverthrow-return-types を使用してください。

例外の発生源を特定する

  1. 現在、失敗がコードに入り込む箇所を特定します。

    • 手書きの try/catch、変換のみに使われている .catch(...) ラッパー、例外を投げることがわかっている API の直接呼び出し、拒否される可能性がある Promise を返す関数を探します。
    • サードパーティライブラリ、パーサー、データベースクライアント、ネットワーククライアント、ファイルシステムヘルパー、スキーマバリデーター、シリアライズ処理を確認します。
  2. ラッパーを選ぶ前に、失敗の形を見分けます。

    • 値を返す前に処理が例外を投げる可能性がある場合は、同期処理用の方法を使います。
    • 処理が Promise を返すものの、その Promise が存在する前に例外を投げる可能性がある場合は、Promise を返す関数用の方法を使います。
    • すでに PromiseLike の値が手元にある場合は、Promise インスタンス用の方法を使います。
  3. すでに Result または ResultAsync を返す API はラップしないでください。

    • map、mapErr、andThen、asyncAndThen、または orElse で直接合成します。

ラッパーを選ぶ

  1. 同期的に例外を投げる関数には、Result.fromThrowable または fromThrowable を使います。

    • Err 側の型を明確にするため、必ずエラーマッパーを渡します。
  2. 返却前に例外を投げる可能性がある、または非同期実行中に失敗する可能性がある Promise 返却関数には、ResultAsync.fromThrowable を使います。

    • 関数呼び出し自体が例外を投げる可能性がある場合は、ResultAsync.fromPromise(fn(...), ...) よりこちらを優先します。
  3. 手元にすでに PromiseLike の値がある場合は、ResultAsync.fromPromise または fromPromise を使います。

    • 拒否された値は、ただちに具体的なエラー型にマッピングします。
  4. 同じエラーの形が繰り返し現れる場合は、用途を絞ったマッパー関数を再利用します。

    • unknown、any、汎用的な文字列よりも、安定したドメインエラーを優先します。

原則として try/catch を避ける

  1. neverthrow のヘルパーで対応できる場合、新たに手書きの try/catch ブロックを追加しないでください。

    • 必要に応じて、リスクのある処理を関数に切り出して、その関数をラップします。
  2. 周囲の構文が本当に必要とする場合に限り、try/catch を残します。

    • 例として、finally が必要なクリーンアップ処理、例外を捕捉して変換する必要があるフレームワーク境界、ラッパーヘルパーだけでは適切に表現できない言語構文などがあります。
  3. try/catch が引き続き必要な場合は、最も狭い境界に置きます。

    • 捕捉した値をただちに Err、または必要なフレームワーク固有のレスポンスに変換します。
    • 型付けされていない unknown のまま、捕捉した値をコードベース内に流さないでください。

実装ルール

  1. 例外を投げる、または拒否される処理の発生源近くで、一度だけラップします。

    • 同じ処理を入れ子にしてラップしないでください。
  2. エラーマッピングを明示します。

    • ローカルのスタイルが許す場合は、処理名、入力識別子、上流のステータスコードなど、有用なコンテキストを保持するマッパー関数を優先します。
  3. neverthrow によってより明確なラッパーを使える場合は、変換のみを行う .catch(...) チェーンを置き換えます。

    • Promise.resolve、Promise.reject、カスタムラッパーオブジェクトを使って ResultAsync を手動で模倣しないでください。

パターンの例

const parseConfig = Result.fromThrowable(
  JSON.parse,
  (error) => ({ type: 'ConfigParseError', cause: error }),
)

const fetchUser = ResultAsync.fromThrowable(
  apiClient.getUser,
  (error) => ({ type: 'UserFetchError', cause: error }),
)

function readBody(): ResultAsync<RequestBody, BodyReadError> {
  return ResultAsync.fromPromise(request.json(), toBodyReadError)
}

完了前に検証する

  1. 新規または編集した失敗の捕捉処理で、該当する箇所に neverthrow のヘルパーを使っていることを確認します。
  2. 各ラッパーの選択が実際の失敗の形(同期的な例外、Promise 返却関数、既存の Promise)に合っていることを確認します。
  3. すべてのエラーマッパーが明示的なエラー型を生成することを確認します。
  4. 残っている try/catch ブロックが、慣習ではなく実際の制約を理由としていることを確認します。
  5. 安全で、かつ作業範囲内であれば、テスト、リンティング、型チェックなど、通常のローカル検証を実行します。

結果を報告する

タスクを完了したら、次の内容を記載してください。

  • どの例外をスローする操作、または拒否する操作をラップしたか。
  • どの neverthrow ヘルパーを使い、その理由は何か。
  • 残っている try/catch ブロックがあれば、その理由と、避けられなかった理由。
  • 捕捉または拒否された値を、どのように明示的なエラー型にマッピングしたか。

コメント