limit-any-type について
根拠のない `any` の使用を避け、`unknown` や用途を絞った型などの代替策を解説する TypeScript スキルです。型の追加、JavaScript からの移行、ライブラリや API の値の扱いに役立ちます。
主な機能
- 01`any` のリスクの説明
- 02不明な値に `unknown` を提案
- 03用途に絞ったインターフェースと型エイリアス
- 04型チェックを回避する典型例の指摘
- 05API データの型設計の案内
活用シーン
- 01エラー回避目的の `any` の置き換え
- 02JavaScript 移行時の型追加
- 03API やライブラリ由来データの型定義
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ marius-townhouse/ effective-typescript-skills --skill limit-any-typeインストール後、Claude Code で/limit-any-typeを入力して読み込まれたか確認します。
詳細
any 型の使用を制限する
概要
any 型を使うと、そのコードに対する TypeScript の型チェッカーが実質的に無効になります。
any は最後の手段として役立つこともありますが、型安全性、開発者エクスペリエンス、リファクタリングへの安心感、バグの防止といった TypeScript の利点を失わせます。
このスキルを使う場面
- 型エラーを黙らせるために any を使おうとしている
- JavaScript コードを TypeScript に移行している
- 型定義のないサードパーティライブラリを扱っている
- 複雑な型エラーに悩まされている
- 既存のコードに型注釈を追加している
絶対に守るルール
NEVER use any without a specific, documented reason.
例外はありません:
- 「とりあえずの応急処置だから」
- 「型が複雑すぎるから」
- 「あとで直すから」
- 「実行時には動くから」
検出:「any の臭い」
any を書こうとしているなら、いったん手を止めて「もっとよい方法はないだろうか?」と考えてください。
// ❌ VIOLATION: Using any because it's "easy"
function processData(data: any) {
return data.items.map((item: any) => item.name);
}
// ✅ CORRECT: Define proper types
interface DataItem {
name: string;
}
interface Data {
items: DataItem[];
}
function processData(data: Data) {
return data.items.map(item => item.name);
}
any の5つの危険性
1. 型安全性がない
let age: number;
age = '12' as any; // No error, but wrong!
age += 1; // "121" at runtime
2. 契約を破る
function calculateAge(birthDate: Date): number { /* ... */ }
let birthDate: any = '1990-01-19'; // string, not Date!
calculateAge(birthDate); // No error, but will fail
3. 言語サービスが使えない
// With proper types: autocomplete, refactoring, documentation
person. // Shows: name, age, email...
// With any: nothing
(person as any). // No autocomplete
4. リファクタリングのバグを見逃す
interface Props {
onSelectItem: (id: number) => void; // Changed from (item: any)
}
function handleSelectItem(item: any) {
selectedId = item.id; // Bug! Should be just `item` now
}
5. 型設計の問題を隠す
// ❌ BAD: What is this state?
const appState: any = { /* ... */ };
// ✅ GOOD: Clear, documented design
interface AppState {
user: User | null;
preferences: UserPreferences;
isLoading: boolean;
}
プレッシャーへの対処法
1. 「複雑すぎる」
プレッシャー:「型が複雑すぎる。any のほうが簡単だ」
**対応:**複雑な型は、複雑なデータを表していることがよくあります。型を定義すれば、データモデルを理解し、文書化することにつながります。
**行動:**型を分解してください。インターフェースと型エイリアスを使いましょう。「このデータは実際にはどのような形をしているのか?」と問いかけてください。
2. 「あとで直す」
プレッシャー:「戻ってきたときに適切な型を追加する」
**対応:**おそらく実行しません。技術的負債は蓄積し、any はコードベース全体に広がります。
**行動:**今すぐ直してください。本当に直せない場合は、チケット番号を付けた // TODO を追加してください。
3. 「ライブラリに型定義がない」
プレッシャー:「この npm パッケージには @types がない」
**対応:**いくつか方法があります。最小限の型定義を書く、unknown を使う、または .d.ts ファイルを作成する方法です。
**行動:**自分で制御できない値には unknown を使ってください。実際に使用するものに絞ったインターフェースを作成してください。
any よりよい代替手段
| 代わりに | 使うもの |
|---|---|
不明な値に any | unknown(型を絞り込む必要がある) |
any[] | unknown[] または具体的な型 |
(x: any) => any | 適切な関数シグネチャ |
Record<string, any> | Record<string, unknown> |
JSON に any | unknown を使って解析・検証する |
危険信号 — 立ち止まって再検討してください
- 1つの関数に複数の
any型がある - エラーを黙らせるために
as anyを使っている - 型チェックを回避するために
// @ts-ignoreまたは@ts-expect-errorを使っている - 公開 API のシグネチャに any がある
- 関数の戻り値の型に any がある
よくある正当化(どれも不適切です)
| 言い訳 | 実際のところ |
|---|---|
| 「実行時には動く」 | 型は実行時より前にバグを見つけるためにあります。 |
| 「TypeScript は厳しすぎる」 | TypeScript はあなたを守っています。何を伝えているのか理解しましょう。 |
| 「型がわからない」 | unknown を使い、型を絞り込んでください。 |
| 「サードパーティライブラリだから」 | 使用するものに必要な最小限の型定義を書いてください。 |
| 「内部コードにすぎない」 | 内部コードもコードです。いずれデバッグすることになります。 |
クイックリファレンス
| 症状 | 対応 |
|---|---|
| 理解できない型エラー | エラーを注意深く読み、unknown を使う |
| 複雑な入れ子の型 | 小さなインターフェースに分割する |
| API からの動的なデータ | レスポンスの型を定義し、境界で検証する |
| JavaScript からの移行 | unknown から始め、段階的に型を追加する |
結論
any はすべて、いつか発生するバグの種です。
わからない値には unknown を使い、わかっている値には適切な型を使ってください。どうしても any を使う必要がある場合は、適用範囲を狭くし、理由を記録して、なくす計画を立ててください。
参考資料
Dan Vanderkam 著『Effective TypeScript』の項目5「any 型の使用を制限する」に基づいています。