mcpField
N
narrow-any-scope

narrow-any-scope

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

narrow-any-scope について

`any` の使用が避けられない場合に、その影響を必要最小限に抑える TypeScript 開発者向けのコーディングスキルです。型定義のない依存コードや複雑な型エラーへの対処、コードレビューに役立ちます。

主な機能

  1. 01代入時に `any` の範囲を限定
  2. 02インラインの `any` アサーション
  3. 03関数の戻り値型を注釈
  4. 04型付き変数で値を制約
  5. 05精密なコールバック型を使用

活用シーン

  1. 01型定義のない外部コードへの対応
  2. 02JavaScript から TypeScript への移行
  3. 03`any` を使うコードのレビュー

インストール

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

$npx skills add https://github.com/marius-townhouse/effective-typescript-skills --skill narrow-any-scope

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

詳細

あらゆる型で可能な限り狭いスコープを使う

概要

anyを使わざるを得ない場合は、被害を封じ込めましょう。

anyには伝染性があり、コード全体に広がります。型安全性への影響を抑えるため、可能な限り狭いスコープに限定してください。

このスキルを使う場面

  • 何らかの理由でanyを使わざるを得ない場合
  • 型定義のないサードパーティコードを扱う場合
  • 複雑な型エラーに対処する場合
  • JavaScriptからTypeScriptへ移行する場合
  • anyを使っているコードをレビューする場合

絶対ルール

NEVER let any escape its minimal necessary scope.

例外はありません:

  • 「変数1つだけだから」
  • 「後で直すから」
  • 「関数が短いから」

検出:「anyが漏れ出している」兆候

anyをもっと狭いスコープにできるなら、そうしてください。

// ❌ VIOLATION: any on parameter escapes to return value
function processExpression(expression: any) {
  const result = expression.evaluate();  // result is any
  return result;                          // Returns any - spreads everywhere
}

// ✅ BETTER: any only where needed
function processExpression(expression: any) {
  const result: number = expression.evaluate();  // Constrain immediately
  return result;                                  // Returns number
}

テクニック1:代入時に範囲を狭める

// ❌ BAD: any spreads
const config = getConfig() as any;
config.debug = true;      // config stays any
const debug = config.debug;  // debug is any

// ✅ GOOD: Constrain immediately
const config = getConfig() as any;
const debug: boolean = config.debug;  // debug is boolean

テクニック2:anyの型アサーションをインラインで使う

// ❌ BAD: any on the whole object
function processObject(obj: any) {
  obj.x = 1;
  obj.y = 2;
  return obj;  // Returns any
}

// ✅ GOOD: any only on the problematic line
function processObject(obj: Foo) {
  // @ts-expect-error - The library typings are wrong here
  (obj as any).secretMethod();
  return obj;  // Returns Foo
}

テクニック3:戻り値の型注釈

// ❌ BAD: Return type infected by any
function parse(input: string) {
  const parsed = JSON.parse(input);  // parsed is any
  return parsed;                      // Return type is any
}

// ✅ GOOD: Explicit return type blocks the any
function parse(input: string): ParsedData {
  const parsed = JSON.parse(input);  // Still any internally
  return parsed;                      // But return type is ParsedData
}

テクニック4:中間変数

// ❌ BAD: any infects the whole expression
function calculate(a: number, b: any, c: number) {
  return a + b + c;  // Result is any because b is any
}

// ✅ BETTER: Convert any before use
function calculate(a: number, b: any, c: number) {
  const bNum: number = b;  // Constrain b to number
  return a + bNum + c;     // Result is number
}

テクニック5:any型の引数ではなく型アサーションを使う

// ❌ BAD: Changing parameter type to any
function processUser(user: any) {
  return user.name.toUpperCase();
}

// ✅ GOOD: Keep the type, assert where needed
function processUser(user: User) {
  // Only use any assertion if absolutely necessary
  return (user as any).secretField;  // any is inline only
}

any[]の落とし穴

// ❌ DANGEROUS: any[] elements are any
function getFirst(arr: any[]) {
  return arr[0];  // Returns any
}

// ✅ SAFER: Use generics or unknown
function getFirst<T>(arr: T[]): T {
  return arr[0];  // Returns T
}

function getFirst(arr: unknown[]): unknown {
  return arr[0];  // Returns unknown - forces checking
}

関数シグネチャ:より正確なany

// ❌ BAD: Maximally broad any
type Callback = any;

// ✅ BETTER: Precise function types
type Callback0 = () => any;           // No params
type Callback1 = (arg: any) => any;   // One param
type CallbackN = (...args: any[]) => any;  // Any params

プレッシャーに負けないためのプロトコル

1. 「この場所だけだから」

プレッシャー:「anyはこの箇所だけにとどまっています」

**回答:**anyは戻り値の型、代入、関数呼び出しを通じて広がります。

**対処:**スコープを狭めてください。すぐに型の制約を追加してください。

2. 「型が複雑すぎる」

プレッシャー:「適切な型がわかりません」

**回答:**一時的にanyを使ってもかまいませんが、出力には制約を設けてください。

**対処:**明示的な戻り値の型を追加してください。中間変数にも型注釈を追加してください。

3. 「内部コードだから」

プレッシャー:「このコードを使う外部コードはありません」

**回答:**将来のあなたにとって、今のあなたのコードは外部コードです。

**対処:**anyのスコープを狭めてください。なぜ必要なのかを記録してください。

危険信号 — 作業を止めて再検討する

  • 関数の引数にanyを使っている
  • anyを返す関数(特に戻り値の型が明示されていない場合)
  • 複数回使われる変数にanyを代入している
  • 式を通じてanyが広がっている
  • 複数の関数間でanyを渡している

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

言い訳実際のところ
「封じ込めている」anyは戻り値や代入を通じて広がります。
「1回しか使わない」それはバグが起こるのを待っているようなものです。
「後で直す」その「後」は決して来ません。今、スコープを狭めてください。
「関数が短い」短い関数でもanyを広げることがあります。

クイックリファレンス

anyの状況範囲を狭めるテクニック
any型の引数戻り値の型注釈を追加する
any型の戻り値明示的な戻り値の型を追加する
式の中のany型付きの変数に代入する
JSON.parse由来のany戻り値の型を追加するか、検証する
ライブラリ由来のany具体的な型にアサーションする

anyの使用状況を監査する

// Before: any everywhere
function process(data: any): any {
  const x = data.foo;        // any
  const y = data.bar;        // any
  return { x, y };           // any
}

// After: any contained
function process(data: any): Result {
  const x: number = data.foo;   // number
  const y: string = data.bar;   // string
  return { x, y };              // Result
}

要点

anyは危険物として扱ってください。漏出を封じ込めましょう。

anyを使わざるを得ない場合は、可能な限り小さなコード片だけで使ってください。型注釈を追加して、広がるのを防ぎましょう。anyが必要な1行を除き、すべての場所で型安全性を保つことが目標です。

参考資料

Dan Vanderkam著「Effective TypeScript」、項目43「Use the Narrowest Possible Scope for any Types」に基づいています。

コメント