こんにちは。TypeScriptの世界へようこそ。
日々の開発で「辞書のようなオブジェクトを作りたい」「APIから来る動的なデータを扱いたい」と思ったとき、真っ先に思い浮かぶのがインデックスシグネチャですよね。
interface UserConfig {
[key: string]: string | number;
}
これを使えばどんなキーでも受け入れられます。しかし、ここで一つ大きな問題が発生します。「何でもアリ」になりすぎて、TypeScriptが本来持っている「型安全」という守護神がどこかへ行ってしまうのです。
今日は、インデックスシグネチャの「緩さ」を、Lookup Types(ルックアップ型)という強力な武器で引き締めるテクニックを伝授します。ここをマスターすれば、あなたのコードは格段に堅牢になりますよ。
—
1. なぜ「インデックスシグネチャ」だけでは足りないのか?
まずは、よくある失敗例を見てみましょう。
interface Settings {
[key: string]: string | number;
}
const mySettings: Settings = {
theme: “dark”,
fontSize: 16,
};
// コンパイラは何も文句を言いません。でも、これが問題の始まりです。
const value = mySettings.unknownKey;
// 実行時は undefined ですが、型上は string | number になってしまいます。
// 「存在しないキー」を「値が存在する」と誤認してしまう。これがバグの温床です。
インデックスシグネチャは「この構造に合致するなら何でもいいよ」という非常に寛大なルールです。しかし、大規模なアプリケーションにおいて「何でもアリ」は恐怖でしかありません。
—
2. 救世主「Lookup Types」で型を束縛する
「特定のキーしか許可したくないが、型定義は動的に保ちたい」。そんなときに使うのが Lookup Types です。
あらかじめ「許可するキー」を型として定義し、それを使ってインデックスシグネチャを絞り込むのです。
// 1. まず、許可するキーのリストを定義します
type ConfigKeys = ‘theme’ | ‘fontSize’ | ‘language’;
// 2. Lookup Typesを使って型を構築する
// [K in ConfigKeys] は「ConfigKeysに含まれるものだけをキーにする」という宣言です
type SafeSettings = {
[K in ConfigKeys]: string | number;
};
const settings: SafeSettings = {
theme: ‘dark’,
fontSize: 16,
language: ‘ja’
};
// 試しに存在しないキーを入れてみましょう
// const error: SafeSettings = {
// unknownKey: ‘oops’ // 型エラー! “unknownKey” は許されていません。
// };
どうですか? インデックスシグネチャの柔軟性を持ちつつ、「許可されていないキー」をコンパイル時に弾くことができました。これがTypeScriptの真の力です。
—
3. さらに先へ:値の型まで厳密に管理する
現場のコードでは、「themeは文字列」「fontSizeは数値」のように、キーごとに値の型が異なることも多いはずです。その場合は、以下のように組み合わせるのがスマートです。
interface AppSchema {
theme: string;
fontSize: number;
isBeta: boolean;
}
// keyof AppSchema は “theme” | “fontSize” | “isBeta” を抽出します
// その後、AppSchema[K] でそれぞれのキーに対応する型を自動で割り当てます
type StrictConfig = {
[K in keyof AppSchema]: AppSchema[K];
};
const config: StrictConfig = {
theme: ‘light’,
fontSize: 14,
isBeta: false
};
これなら、`AppSchema` を修正するだけで、`StrictConfig` も自動的に追従します。「型を一度定義したら、あとはコンパイラに計算させる」。これこそが、メンテナンス性の高いコードの極意です。
—
4. 陥りやすい罠:その「インデックスシグネチャ」は本当に必要?
最後に、一つだけアドバイスです。
初心者のうちは、何でも `[key: string]: any` のようにインデックスシグネチャで逃げたくなります。しかし、本当に動的なキーアクセスが必要ですか?
もし、キーの種類があらかじめ決まっているのであれば、インデックスシグネチャを使わず、Mapped Types(先ほど紹介した `[K in …]` の記法) を使ってください。
- インデックスシグネチャ: 「どんなキーが来るかわからない」という諦め。
- Mapped Types + Lookup Types: 「型を賢く制御する」という設計。
この違いを意識するだけで、あなたの書くTypeScriptの質は、今日から劇的に向上します。
—
まとめ
1. インデックスシグネチャ単体は「緩すぎる」。可能な限り避けよう。
2. キーを制限したいなら `[K in KeyType]` を使おう。
3. 値の型を自動追従させたいなら `keyof T` と `T[K]` を組み合わせよう。
TypeScriptは、単なるJavaScriptの拡張ではありません。「型」という設計図をコードに書き込むことで、実行前のバグをゼロに近づけるための最強のツールです。
ここを理解できたあなたは、もうTypeScriptの基本をマスターしたと言っても過言ではありません。次はぜひ、この知識を実際のプロジェクトで使ってみてください。きっと、コードの「手応え」が変わるはずですよ。
それでは、良いコーディングライフを!