Claude Code Plugins

Community-maintained marketplace

Feedback

数値の入出力バリデーション方針。関数の引数・戻り値の妥当性チェック規約を定義。test-writer, implement, reviewerの各観点で参照。

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name validation-policy
description 数値の入出力バリデーション方針。関数の引数・戻り値の妥当性チェック規約を定義。test-writer, implement, reviewerの各観点で参照。
allowed-tools Read

数値バリデーション方針

このプロジェクトにおける数値の入出力バリデーションの統一方針を定義します。

基本原則

1. すべての公開関数は入力を検証する

  • 外部からの入力は信頼しない
  • 関数の最初で引数の妥当性をチェック
  • 不正な入力には早期にエラーをスロー

2. 一貫したエラーハンドリング

  • 同じ種類の不正入力には同じエラーメッセージを使用
  • エラーメッセージは日本語で明確に
  • throw new Error()を使用(カスタムエラーは現時点では不要)

3. 型だけでは不十分

  • TypeScriptの型チェックは実行時には働かない
  • 数値の範囲、整数性、有限性を実行時に検証

バリデーションチェック項目

必須チェック(すべての数値引数)

1. 有限値チェック

if (!Number.isFinite(value)) {
  throw new Error('適切なエラーメッセージ');
}

検出する値: Infinity, -Infinity, NaN

理由:

  • NaNは比較演算が予期しない結果になる(NaN === NaNfalse
  • Infinityは算術演算で予期しない振る舞いをする

2. 整数チェック(整数値を期待する引数)

if (!Number.isInteger(value)) {
  throw new Error('適切なエラーメッセージ');
}

検出する値: 1.5, 3.14, 0.1など

理由: ダーツの点数は整数のみ有効

条件付きチェック(要件に応じて)

3. 範囲チェック

if (value < min || value > max) {
  throw new Error('適切なエラーメッセージ');
}

:

  • 残り点数: > 0(正の整数)
  • 投擲点数: 0 <= value <= 60
  • 座標値: プロジェクト固有の範囲

4. ドメイン固有のチェック

if (!VALID_SCORES.has(value)) {
  throw new Error('適切なエラーメッセージ');
}

: 有効なダーツスコア(23, 29などは無効)

チェック順序の原則

必ず以下の順序で実行:

  1. 有限値チェック (Number.isFinite())
  2. 整数チェック (Number.isInteger())
  3. 範囲チェック (最小値・最大値)
  4. ドメイン固有チェック (業務ルール)

理由: 早い段階で基本的な不正入力を排除し、より複雑なチェックに進む

実装パターン

パターン1: 整数 + 正の値

export function exampleFunction(score: number): void {
  // 入力値の妥当性チェック
  if (!Number.isFinite(score) || !Number.isInteger(score)) {
    throw new Error('点数は整数である必要があります');
  }

  if (score <= 0) {
    throw new Error('点数は正の整数である必要があります');
  }

  // ビジネスロジック...
}

パターン2: 整数 + 範囲指定

export function exampleFunction(throwScore: number): void {
  // 入力値の妥当性チェック
  if (!Number.isFinite(throwScore) || !Number.isInteger(throwScore)) {
    throw new Error('投擲点数は整数である必要があります');
  }

  if (throwScore < 0 || throwScore > 60) {
    throw new Error('投擲点数は0以上60以下である必要があります');
  }

  // ビジネスロジック...
}

パターン3: 有限値のみ(整数制約なし)

export function exampleFunction(coordinate: number): void {
  // 入力値の妥当性チェック
  if (!Number.isFinite(coordinate)) {
    throw new Error('座標は有限の数値である必要があります');
  }

  // ビジネスロジック...
}

エラーメッセージの統一

標準メッセージテンプレート

チェック内容 メッセージ例
有限値チェック(整数期待) {パラメータ名}は整数である必要があります
有限値チェック(実数可) {パラメータ名}は有限の数値である必要があります
正の整数 {パラメータ名}は正の整数である必要があります
範囲指定 {パラメータ名}は{最小値}以上{最大値}以下である必要があります

注意: 有限値と整数を同時にチェックする場合、エラーメッセージは「整数である必要があります」とする(NaNInfinityも整数ではないため)

test-writerの観点

テストケース作成時の必須項目

1. 異常系テスト - 入力検証

各関数に対して以下のテストケースを作成:

describe('入力検証', () => {
  test('NaNはエラーをスローする', () => {
    expect(() => targetFunction(NaN)).toThrow('適切なエラーメッセージ');
  });

  test('Infinityはエラーをスローする', () => {
    expect(() => targetFunction(Infinity)).toThrow('適切なエラーメッセージ');
  });

  test('-Infinityはエラーをスローする', () => {
    expect(() => targetFunction(-Infinity)).toThrow('適切なエラーメッセージ');
  });

  test('小数値(整数期待の場合)はエラーをスローする', () => {
    expect(() => targetFunction(2.5)).toThrow('適切なエラーメッセージ');
  });

  test('範囲外の値はエラーをスローする', () => {
    expect(() => targetFunction(-1)).toThrow('適切なエラーメッセージ');
    expect(() => targetFunction(999)).toThrow('適切なエラーメッセージ');
  });
});

2. テストの優先順位

  1. 正常系: 期待される入力での動作
  2. 境界値: 有効範囲の境界(最小値、最大値)
  3. 異常系 - 型レベル: NaN, Infinity, 非整数
  4. 異常系 - 範囲: 負の値、範囲外
  5. 異常系 - ドメイン: ドメイン固有の不正値

implementの観点

実装時のチェックリスト

  • すべての数値引数に対してバリデーションを実装
  • バリデーションは関数の最初に配置
  • チェック順序は「有限値 → 整数 → 範囲 → ドメイン」
  • エラーメッセージは統一テンプレートに従う
  • JSDocに@throwsタグを追加
  • JSDocの@paramに「正の整数のみ」などの制約を明記

JSDocの記載例

/**
 * 残り点数がダブルでフィニッシュ可能かを判定する
 *
 * @param remainingScore 残り点数(正の整数のみ)
 * @returns ダブルでフィニッシュ可能ならtrue、不可能ならfalse
 * @throws {Error} 入力値が不正な場合
 */
export function canFinishWithDouble(remainingScore: number): boolean {
  // 入力値の妥当性チェック
  if (!Number.isFinite(remainingScore) || !Number.isInteger(remainingScore)) {
    throw new Error('残り点数は整数である必要があります');
  }

  // ...
}

reviewerの観点

レビュー時のチェックポイント

1. 入力検証の完全性

  • すべての数値引数にバリデーションがあるか
  • Number.isFinite()チェックがあるか
  • 整数が期待される場合、Number.isInteger()チェックがあるか
  • 範囲チェックが適切か

2. 一貫性

  • 同じ種類のパラメータ(例: 残り点数)は同じバリデーションか
  • エラーメッセージは統一テンプレートに従っているか
  • チェック順序は「有限値 → 整数 → 範囲 → ドメイン」か

3. テストカバレッジ

  • NaN, Infinity, -Infinityのテストがあるか
  • 小数値のテストがあるか(整数期待の場合)
  • 範囲外のテストがあるか

4. ドキュメント

  • JSDocに@throwsタグがあるか
  • JSDocの@paramに制約が明記されているか

レビュー時の指摘例

不十分な例:

export function example(score: number): void {
  if (score <= 0) {
    return false;
  }
  // ...
}

指摘内容:

  • NaN, Infinityのチェックがない
  • 整数チェックがない
  • エラーをスローせずにfalseを返している(一貫性がない)

改善例:

export function example(score: number): void {
  if (!Number.isFinite(score) || !Number.isInteger(score)) {
    throw new Error('点数は整数である必要があります');
  }

  if (score <= 0) {
    throw new Error('点数は正の整数である必要があります');
  }
  // ...
}

よくある間違い

❌ 間違い1: typeofによる型チェック

if (typeof value !== 'number') {
  throw new Error('数値である必要があります');
}

問題: NaNInfinitytypeofでは'number'になる

正しい方法: Number.isFinite()を使用

❌ 間違い2: value % 1 === 0での整数チェック

if (value % 1 !== 0) {
  throw new Error('整数である必要があります');
}

問題: Infinity % 1NaNになり、NaN !== 0で一見動作するが意図が不明確

正しい方法: Number.isInteger()を使用

❌ 間違い3: エラーをスローせずにfalseを返す

export function validate(value: number): boolean {
  if (value < 0) {
    return false; // ❌
  }
  return true;
}

問題:

  • 不正な入力と正常な処理結果の区別がつかない
  • 関数の使用者がエラーハンドリングを忘れる可能性

正しい方法: 不正な入力にはエラーをスロー

❌ 間違い4: チェック順序の誤り

if (value <= 0) {
  throw new Error('正の整数である必要があります');
}

if (!Number.isInteger(value)) {
  throw new Error('整数である必要があります');
}

問題: NaNInfinityが先の条件(<= 0)をすり抜ける可能性

正しい方法: 有限値・整数チェックを先に実行

既存コードとの一貫性

このプロジェクトの既存実装例(参照用):

  • checkBust (src/utils/gameLogic.ts:24-36): 残り点数と投擲点数の検証
  • canFinishWithDouble (src/utils/gameLogic.ts:84-87): 残り点数の検証

新しい関数を追加する際は、これらと同じパターンに従ってください。

まとめ

必ず守るべき3つのルール

  1. すべての数値引数を検証する - Number.isFinite()Number.isInteger()(必要に応じて)
  2. チェック順序を守る - 有限値 → 整数 → 範囲 → ドメイン
  3. エラーメッセージを統一する - 標準テンプレートを使用

これらのルールに従うことで、堅牢で保守性の高いコードベースを維持できます。