mcpField
A
avoid-repeated-params

avoid-repeated-params

github.com/marius-townhouse開発642 回インストール38 週間前に更新
リポジトリ

avoid-repeated-params について

同じ型の引数が複数ある場合に、誤用しにくい関数シグネチャを設計する TypeScript スキルです。位置引数を取り違えやすいときは、名前付きのオブジェクト引数を推奨します。

主な機能

  1. 01混同しやすい引数にはオブジェクトを使用
  2. 02呼び出しを自己説明的にする
  3. 03関連する値を意味でまとめる
  4. 04明確な慣例がある場合は位置引数を維持

活用シーン

  1. 01複数の文字列引数を持つ API の設計
  2. 02日付フォーマット引数の明確化
  3. 03矩形の位置とサイズのグループ化

インストール

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

$npx skills add https://github.com/marius-townhouse/effective-typescript-skills --skill avoid-repeated-params

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

詳細

同じ型のパラメーターを繰り返さない

概要

同じ型のパラメーターが複数あると、取り違えが起きやすくなります。

関数が (string, string, string) を受け取る場合、引数の順序を間違えて渡しがちです。名前付きパラメーター(オブジェクト)を使えば、呼び出し自体が自己説明的になります。

このスキルを使う場面

  • 同じ型のパラメーターを2つ以上持つ関数
  • 取り違えやすいパラメーター
  • ユーザーが頻繁に呼び出す API
  • 分かりにくい関数シグネチャーのリファクタリング

絶対に守るルール

If parameter order is confusing, use an object.
Names prevent mix-ups better than positions.

覚えておきましょう:

  • TypeScript では、同じ型の引数の入れ替わりを検出できません
  • 位置に基づく API を使うには、ドキュメントを確認する必要があります
  • オブジェクトパラメーターは自己説明的です
  • IDE の自動補完は、名前付きパラメーターのほうが効果的に機能します

検出:取り違えやすいケース

function sendEmail(
  to: string,
  subject: string,
  body: string
) { /* ... */ }

// Which is which?
sendEmail(
  'Hello!',
  '[email protected]',
  'Welcome to our service'
);
// Whoops! Subject and recipient are swapped

TypeScript には (string, string, string) と認識されます。すべて有効なため、エラーは発生しません。

解決策:オブジェクトパラメーター

function sendEmail(params: {
  to: string;
  subject: string;
  body: string;
}) { /* ... */ }

// Now it's clear:
sendEmail({
  to: '[email protected]',
  subject: 'Hello!',
  body: 'Welcome to our service'
});

// Wrong order is obvious:
sendEmail({
  to: 'Hello!',  // Clearly wrong
  subject: '[email protected]',  // Obviously an email
  body: 'Welcome'
});

位置に基づく方法が適切な場合

型が異なる場合
// Clear: types are different
function setProperty(obj: object, key: string, value: unknown) { }

// Clear: number vs string
function pad(str: string, length: number) { }
パラメーターが1つの場合
// Nothing to confuse
function greet(name: string) { }
よく知られた慣例がある場合
// Math functions are universally position-based
function max(a: number, b: number) { }

// Array methods follow established patterns
function slice(arr: any[], start: number, end: number) { }

すっきり実装するための分割代入

// Clean function signature and implementation
function sendEmail({
  to,
  subject,
  body
}: {
  to: string;
  subject: string;
  body: string;
}) {
  console.log(`Sending to ${to}: ${subject}`);
  // Use to, subject, body directly
}

デフォルト値を持つオプションのパラメーター

interface SendEmailOptions {
  to: string;
  subject: string;
  body: string;
  cc?: string[];
  priority?: 'high' | 'normal' | 'low';
}

function sendEmail({
  to,
  subject,
  body,
  cc = [],
  priority = 'normal'
}: SendEmailOptions) {
  // ...
}

// Call with just required params
sendEmail({ to: '[email protected]', subject: 'Hi', body: 'Hello!' });

// Or with optional params
sendEmail({
  to: '[email protected]',
  subject: 'Urgent',
  body: 'Please respond',
  priority: 'high'
});

必須パラメーターとオプションのパラメーターの併用

// Required first parameter, options object second
function createElement(
  tagName: string,
  options?: {
    className?: string;
    id?: string;
    children?: Element[];
  }
) { /* ... */ }

createElement('div');
createElement('div', { className: 'container', id: 'main' });

実例:日付のフォーマット

// Bad: which is format, which is locale?
function formatDate(date: Date, format: string, locale: string): string { }

formatDate(new Date(), 'en-US', 'YYYY-MM-DD');  // Wrong order!

// Good: named parameters
function formatDate(
  date: Date,
  options: { format: string; locale: string }
): string { }

formatDate(new Date(), { format: 'YYYY-MM-DD', locale: 'en-US' });

長方形の例

// Bad: easy to confuse width/height, x/y
function drawRect(x: number, y: number, width: number, height: number) { }

// Better: grouped semantically
function drawRect(
  position: { x: number; y: number },
  size: { width: number; height: number }
) { }

// Best: named everything
interface DrawRectOptions {
  x: number;
  y: number;
  width: number;
  height: number;
}
function drawRect(options: DrawRectOptions) { }

プレッシャーへの対処

1. 「冗長すぎる」

主張:「オブジェクト構文は長くなります」

**回答:**一度の冗長さで、継続的な混乱を防げます。

**対応:**明確さを優先して名前付きパラメーターを使いましょう。簡潔さは、バグを招くリスクに見合いません。

2. 「標準的なパターンだ」

主張:「ほかのライブラリは位置指定のパラメーターを使っています」

**回答:**あなたはほかのライブラリではありません。API を分かりやすくしましょう。

**対応:**慣例ではなく、ユーザーのために設計しましょう。

要注意の兆候 — 作業を止めて再検討する

  • 同じ型のパラメーターを2つ以上持つ関数
  • パラメーターの順序を説明するためにドキュメントが必要
  • パラメーターの順序を検証するテスト
  • 引数の入れ替えによるバグ

よくある自己正当化(すべて誤り)

言い訳実態
「パラメーターは2つだけです」文字列が2つでも、取り違える可能性はあります
「IDE にパラメーター名が表示されます」名前は表示されますが、正しい順序は強制されません
「十分なドキュメントがあります」ドキュメントは読まれません

クイックリファレンス

// DON'T: Same-type positional parameters
function fn(a: string, b: string, c: string) { }
fn('x', 'y', 'z');  // What's what?

// DO: Named parameters
function fn(params: { a: string; b: string; c: string }) { }
fn({ a: 'x', b: 'y', c: 'z' });  // Clear!

// OK: Different types
function fn(name: string, count: number) { }

// OK: Single parameter
function fn(message: string) { }

要点

名前付きパラメーターは、引数の取り違えを防ぎます。

関数が同じ型のパラメーターを複数受け取る場合は、オブジェクトパラメーターを使いましょう。わずかな冗長さは、バグの防止と可読性の向上によって何倍にもなって返ってきます。

参考文献

Dan Vanderkam 著『Effective TypeScript』の項目38「同じ型のパラメーターを繰り返さない」に基づいています。

コメント