mcpField
I
imprecise-over-inaccurate

imprecise-over-inaccurate

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

imprecise-over-inaccurate について

型を狭くすることより、実態に合った正確さを優先する TypeScript のスキルです。有効なコードを拒否する型を避け、実行時検証を使う場面を判断できます。

主な機能

  1. 01狭さより正確さを優先
  2. 02誤検知の型エラーを把握
  3. 03複雑な領域には広い型
  4. 04型を段階的に精緻化
  5. 05不確かな値を実行時に検証

活用シーン

  1. 01精密な型が有効な入力を拒否
  2. 02複雑なジェネリック型のデバッグ
  3. 03CSS や外部データの型付け
  4. 04柔軟な JSON Schema 型の設計

インストール

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

$npx skills add https://github.com/marius-townhouse/effective-typescript-skills --skill imprecise-over-inaccurate

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

詳細

不正確な型よりも、不厳密でも正確な型を優先する

概要

不厳密でも正確な型は、厳密でも不正確な型より優れています。

型をより厳密にすると、不正確になるリスクがあります。不正確な型は、誤検知(有効なコードが拒否される)や見逃し(無効なコードが受け入れられる)の原因になります。どちらも型システムへの信頼を損ないます。

このスキルを使う場面

  • 型を「より厳密」にするとき
  • 予期しない型エラーが発生するとき
  • 有効なユースケースを拒否する型があるとき
  • 複雑なジェネリック型をデバッグするとき

絶対的なルール

Types should never reject valid code.
When in doubt, be less precise.

覚えておきましょう:

  • 誤検知(有効なコードを拒否すること)は信頼を損ないます
  • 見逃し(無効なコードを受け入れること)はバグの原因になります
  • 不厳密でも正確な型 > 厳密でも不正確な型
  • 複雑な型はデバッグが困難です

検出:過度に厳密な型

// Attempt to precisely type CSS colors
type CSSColor =
  | 'red' | 'blue' | 'green' | 'yellow' // named colors
  | `#${string}`                        // hex colors
  | `rgb(${number}, ${number}, ${number})`; // rgb

function setColor(color: CSSColor) { /* ... */ }

// But this valid CSS is rejected:
setColor('rgb(255,255,255)');  // Error: no spaces around commas!
setColor('rgba(0, 0, 0, 0.5)');  // Error: didn't account for rgba!

この厳密な型は不正確であり、有効な CSS を拒否します。

より良い方法:不厳密でも正確な型

// Less precise, but accepts all valid CSS colors
function setColor(color: string) { /* ... */ }

setColor('rgb(255, 255, 255)');  // OK
setColor('rgba(0, 0, 0, 0.5)');  // OK
setColor('invalid');             // OK (imprecise)

string 型は不厳密ですが(無効な色も受け入れます)、正確です(有効な色を拒否することはありません)。

中間案:部分的な厳密さ

// Provide known values, allow escape hatch
type CSSColor = 
  | 'red' | 'blue' | 'green' | 'yellow'
  | (string & {});  // Allows any string with autocomplete for known values

setColor('red');     // Autocomplete works
setColor('custom');  // Still allowed

実例:JSON スキーマ

// Trying to precisely type JSON Schema
interface JSONSchema {
  type: 'string' | 'number' | 'object' | 'array' | 'boolean' | 'null';
  properties?: Record<string, JSONSchema>;
  items?: JSONSchema;
  // ... 50 more properties
}

// But real JSON Schema is more flexible:
const schema: JSONSchema = {
  type: ['string', 'null'],  // Error: type can be array!
  // ...
};

「厳密な」型は不正確です。よりシンプルな型のほうが適している場合があります。

interface JSONSchema {
  type?: string | string[];
  [key: string]: unknown;  // Allow any other properties
}

厳密さが役立つ場合

次の場合は、厳密にする価値があります。

  1. すべての入力を自分で管理している(内部型)
  2. 対象の範囲が明確に定義されている(有限で、値が既知)
  3. エラーを早期に検出できる(開発時)
  4. 型が十分にシンプルで、明らかに正しいと判断できる
// Good use of precision: finite, known values
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';

// Good use of precision: simple domain
type PositiveInteger = number;  // (Could use branded type)

厳密さを緩める場合

次の場合は、厳密さを緩めましょう。

  1. 外部データを扱う(API、ユーザー入力)
  2. 対象の範囲が複雑である(CSS、HTML、正規表現)
  3. 型が有効なユースケースを拒否する
  4. 型が複雑で、正しさを確認しにくい
// Over-precise: might reject valid CSS
type CSSLength = `${number}px` | `${number}em` | `${number}rem`;

// Better: trust the developer
type CSSLength = string;

// Or: document the expected format
/** CSS length value, e.g., "10px", "2em" */
type CSSLength = string;

誤検知と見逃しの比較

問題影響解決策
誤検知有効なコードが拒否される型の厳密さを緩める
見逃し無効なコードが受け入れられる実行時に検証する

誤検知のほうが深刻です。理由は次のとおりです。

  • 正当な作業を妨げる
  • 回避策(as any)が必要になる
  • TypeScript への信頼を損なう

段階的な調整

まずは不厳密に始め、必要に応じて厳密さを加えます。

// V1: Start broad
interface Config {
  [key: string]: unknown;
}

// V2: Add known properties
interface Config {
  port?: number;
  host?: string;
  [key: string]: unknown;  // Still allow extras
}

// V3: Remove index signature if confident
interface Config {
  port: number;
  host: string;
}

圧力に対抗するための手順

1. 「より厳密なほうが良い」

圧力:「型はできるだけ具体的であるべきです」

**回答:**正確でもある場合に限ります。厳密でも誤っていれば、より悪い結果になります。

**対応:**確認しましょう。この厳密さによって、有効なコードが拒否されませんか?

2. 「すべてのエラーを捕捉すべき」

圧力:「型によって、すべての無効な値を防ぐべきです」

**回答:**すべてを型チェックすることはできません。実行時検証があります。

**対応:**正確に型付けできる部分に型を付け、残りは実行時に検証しましょう。

危険信号 — STOPして再検討しましょう

  • ユニオン型やインターセクション型を多用した複雑な型
  • 有効だと分かっているコードで型エラーが発生する
  • 型を回避するために as any を頻繁に使う
  • 説明が難しい型

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

言い訳実態
「型としては技術的に正しい」有効なコードを拒否するなら、正しくありません
「ユーザーはもっと良いコードを書くべき」型は理想ではなく、現実に合わせるべきです
「例外を追加できる」例外が必要なら、その型は間違っています

クイックリファレンス

// DON'T: Over-precise type that rejects valid code
type Color = 'red' | 'blue' | `#${string}`;
setColor('rgb(0,0,0)');  // Error - but it's valid!

// DO: Imprecise type that accepts all valid code
type Color = string;
setColor('rgb(0,0,0)');  // OK

// BETTER: Partial precision with escape hatch
type Color = 'red' | 'blue' | (string & {});
setColor('red');         // Autocomplete works
setColor('rgb(0,0,0)');  // Still allowed

要点

厳密さより正確さが重要です。

無効な値を一部受け入れる型のほうが、有効な値を拒否する型より優れています。型をより厳密にする場合は、正確さが保たれていることを確認しましょう。厳密さによって誤検知が起きるなら、厳密さを緩めてください。

参考資料

Dan Vanderkam 著「Effective TypeScript」の項目 40「不正確な型よりも不厳密な型を優先する」に基づいています。

コメント