avoid-repeated-params について
同じ型の引数が複数ある場合に、誤用しにくい関数シグネチャを設計する TypeScript スキルです。位置引数を取り違えやすいときは、名前付きのオブジェクト引数を推奨します。
主な機能
- 01混同しやすい引数にはオブジェクトを使用
- 02呼び出しを自己説明的にする
- 03関連する値を意味でまとめる
- 04明確な慣例がある場合は位置引数を維持
活用シーン
- 01複数の文字列引数を持つ API の設計
- 02日付フォーマット引数の明確化
- 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「同じ型のパラメーターを繰り返さない」に基づいています。