excess-property-checking について
余剰プロパティチェックと通常の型チェックの違いを解説する TypeScript 学習スキルです。オブジェクトリテラルのエラーやプロパティ名の誤記を理解し、安全でない回避を避けるのに役立ちます。
主な機能
- 01オブジェクトリテラルへのチェックを解説
- 02変数経由の代入との違いを比較
- 03型アサーションによる回避を説明
- 04オプション項目の誤記検出を紹介
- 05弱い型へのチェックを解説
活用シーン
- 01余剰プロパティのエラー差の調査
- 02オプション設定項目名の確認
- 03インデックスシグネチャの適否の判断
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ marius-townhouse/ effective-typescript-skills --skill excess-property-checkingインストール後、Claude Code で/excess-property-checkingを入力して読み込まれたか確認します。
詳細
余分なプロパティチェックと型チェックの違い
概要
オブジェクトリテラルは特別に扱われ、TypeScript は未知のプロパティを検出します。
これにより、構造的型付けでは見逃されるタイプミスや間違いを検出できます。ただし、これはオブジェクトリテラルにのみ適用されます。この違いを理解しておくと、混乱を避けられます。
このスキルを使う場面
- オブジェクトリテラルを型付き変数に代入する場合
- 余分なプロパティがエラーになる場合とならない場合がある理由が分からない場合
- 中間変数を使うとエラーが消える場合
- タイプミスが起こりやすいオプショナルプロパティを扱う場合
- オプショナルフィールドの多いインターフェースを設計する場合
絶対に守るルール
ALWAYS remember: Excess property checking only applies to OBJECT LITERALS.
覚えておきましょう:
- オブジェクトリテラル → 余分なプロパティが検出される
- 変数の代入 → 構造的型付けが適用される
- 型アサーション → 余分なプロパティチェックを回避する
検出:「余分なプロパティ」エラー
「Object literal may only specify known properties」というメッセージが表示された場合、余分なプロパティチェックが行われています。
interface Room {
numDoors: number;
ceilingHeightFt: number;
}
// Excess property checking: Error!
const r: Room = {
numDoors: 1,
ceilingHeightFt: 10,
elephant: 'present',
// ~~~~~~~ Object literal may only specify known properties,
// and 'elephant' does not exist in type 'Room'
};
// Same value via intermediate variable: No error!
const obj = {
numDoors: 1,
ceilingHeightFt: 10,
elephant: 'present',
};
const r2: Room = obj; // OK - structural typing allows this
余分なプロパティチェックが存在する理由
構造的型付けは強力ですが、許容範囲が広い仕組みです。余分なプロパティを許すため、バグが隠れてしまうことがあります。
interface Options {
title: string;
darkMode?: boolean;
}
function createWindow(options: Options) {
if (options.darkMode) {
setDarkMode();
}
}
// Without excess property checking, this typo would be silent:
createWindow({
title: 'Spider Solitaire',
darkmode: true // lowercase 'm' - TYPO!
// ~~~~~~~ Object literal may only specify known properties,
// but 'darkmode' does not exist in type 'Options'.
// Did you mean to write 'darkMode'?
});
余分なプロパティチェックが適用される場面
| コンテキスト | 余分なプロパティチェック |
|---|---|
| オブジェクトリテラルを型付き変数に代入する | はい |
| オブジェクトリテラルを関数の引数として渡す | はい |
| オブジェクトリテラルを戻り値として返す | はい |
| 変数を型付き変数に代入する | いいえ |
| 型アサーション | いいえ |
interface Point { x: number; y: number; }
// Object literal - checking applies
const p1: Point = { x: 1, y: 2, z: 3 }; // Error: 'z' not in Point
// Variable - checking does NOT apply
const temp = { x: 1, y: 2, z: 3 };
const p2: Point = temp; // OK
// Type assertion - checking does NOT apply
const p3 = { x: 1, y: 2, z: 3 } as Point; // OK (but bad practice)
余分なプロパティチェックが役立つ場面
オプショナルプロパティのタイプミスを検出する
interface Config {
logLevel?: 'debug' | 'info' | 'warn' | 'error';
timeout?: number;
retries?: number;
}
const config: Config = {
loglevel: 'debug', // Error: Did you mean 'logLevel'?
timeout: 5000,
};
間違ったプロパティ名を防ぐ
interface User {
firstName: string;
lastName: string;
}
const user: User = {
first_name: 'John', // Error: Did you mean 'firstName'?
last_name: 'Doe', // Error: Did you mean 'lastName'?
};
余分なプロパティチェックを回避する(意図的な場合)
既知の余分なプロパティにはインデックスシグネチャを使う
interface Options {
darkMode?: boolean;
[otherOptions: string]: unknown;
}
const o: Options = { darkmode: true }; // OK now
中間変数を使う
const options = { title: 'Game', extraProp: true };
createWindow(options); // OK - excess checking skipped
弱い型:関連するチェック
「弱い」型にはオプショナルプロパティしかありません。TypeScript は特別なチェックを追加します。
interface LineChartOptions {
logscale?: boolean;
invertedYAxis?: boolean;
areaChart?: boolean;
}
const opts = { logScale: true }; // Note: capital 'S'
setOptions(opts);
// ~~~~ Type '{ logScale: boolean; }' has no properties in common
// with type 'LineChartOptions'
このチェックは、通常の余分なプロパティチェックとは異なり、中間変数を介した場合にも適用されます。
よくある間違い
間違い 1:構造的型付けでタイプミスを検出できると思い込む
// ❌ Typo passes silently because no excess property checking
const options = { darkmode: true }; // lowercase 'm'
const config: Options = options; // No error!
// ✅ Use object literal for catching typos
const config: Options = { darkmode: true }; // Error caught!
間違い 2:エラーを黙らせるために型アサーションを使う
// ❌ Assertion bypasses the check
const config = { darkmode: true } as Options;
// ✅ Fix the typo instead
const config: Options = { darkMode: true };
間違い 3:エラーが消える理由について混乱する
// This has an error
const p: Point = { x: 1, y: 2, z: 3 };
// Why doesn't this?
const temp = { x: 1, y: 2, z: 3 };
const p: Point = temp;
// Answer: Excess property checking only applies to object literals!
圧力に負けないためのプロトコル
1. 「as Typeを追加すればいい」
圧力:「型アサーションを使えばエラーが消えます」
**回答:**アサーションは安全性チェックを回避します。実際の問題を修正しましょう。
**対応:**プロパティ名を正すか、型定義を更新します。
2. 「TypeScript は厳しすぎる」
圧力:「余分なプロパティは問題にならないはずです」
**回答:**これにより、オプショナルフィールドのタイプミスなど、実際のバグを検出できます。
**対応:**本当に余分なプロパティが必要な場合は、インデックスシグネチャを使います。
3. 「変数を使えばうまくいく」
圧力:「エラーを避けるために中間変数を使えばいい」
**回答:**それではバグが隠れてしまいます。このエラーには理由があります。
**対応:**余分なプロパティが存在する理由を調べます。
危険信号 — いったん止まって再検討する
- 余分なプロパティエラーを黙らせるために型アサーションを使っている
- チェックを回避するためだけに中間変数を作っている
- 代入によってエラーになる場合とならない場合がある理由が分からない
- 余分なプロパティに対する TypeScript の挙動に一貫性がないと思っている
よくある正当化(すべて不適切)
| 言い訳 | 実際のところ |
|---|---|
| 「余分なプロパティがあるだけです」 | 余分なプロパティは、多くの場合タイプミスを示しています |
| 「構造的型付けなら許されます」 | オブジェクトリテラルには、正当な理由からより厳しいルールが適用されます |
| 「アサーションで直ります」 | アサーションはバグを隠すだけで、修正はしません |
クイックリファレンス
| ケース | 余分なプロパティチェック | 例 |
|---|---|---|
| オブジェクトリテラルを型付き変数に代入 | はい | const x: T = { ... } |
| オブジェクトリテラルを引数として渡す | はい | fn({ ... }) |
| 変数を型付き変数に代入 | いいえ | const temp = {...}; const x: T = temp; |
| 型アサーション | いいえ | { ... } as T |
| 弱い型(変数経由) | 共通するプロパティをチェック | 特殊なケース |
要点
余剰プロパティチェックは、構造的型付けでは見逃されるバグを検出します。
このチェックはオブジェクトリテラルにのみ適用され、変数には適用されません。これは意図的な仕様です。特にオプショナルプロパティの名前の入力ミスを検出できます。型アサーションや中間変数で回避するのではなく、根本的な問題を修正してください。
参考資料
Dan Vanderkam 著『Effective TypeScript』項目 11「余剰プロパティチェックと型チェックを区別する」に基づいています。