TypeScriptインデックスシグネチャのモデルケース

TypeScriptは、JavaScriptに型安全を加えた言語で、静的型付けの利点を享受できます。
その中で「インデックスシグネチャ」は、オブジェクトのプロパティ名やキーが動的である場合に便利な機能です。

インデックスシグネチャを使用すると、予測できないキーを扱いながらも、型安全を保つことができます。今回はTypeScriptのインデックスシグネチャを活用事例(モデルケース)を紹介し、その使い方を解説します。

1. インデックスシグネチャとは?

インデックスシグネチャとは、オブジェクトのプロパティが事前に決まっていない場合に、そのプロパティの名前と型を動的に指定できる仕組みです。例えば、ユーザーが入力した動的なキーで値を管理する場合や、リストや辞書のようにキーが不確定なオブジェクトを扱う場合に役立ちます。

インデックスシグネチャの基本的な構文は以下の通りです。

interface MyObject {
  [key: string]: number;
}

このコードは、「keyという名前のプロパティ(任意の文字列)を持ち、その値がnumber型であるオブジェクト」を定義しています。つまり、MyObject型のオブジェクトでは、文字列のキーに対して数値が格納されることが保証されます。

2. 実際の例:動的なプロパティの追加

では、具体的な例を見てみましょう。以下のコードは、動的にプロパティを追加していくオブジェクトを作成する場合です。

interface UserScores {
  [username: string]: number;
}

const scores: UserScores = {
  "Alice": 90,
  "Bob": 85
};

// 動的にプロパティを追加
scores["Charlie"] = 88;

console.log(scores);

このコードでは、UserScoresというインターフェースを定義し、そのインターフェースには任意のstring型のキーに対してnumber型の値が設定されることを示しています。scoresオブジェクトには、動的にユーザー名(username)をキーとしてスコア(number型)を追加しています。このように、インデックスシグネチャを使用することで、事前にどのキーが使われるかを決めなくても柔軟にプロパティを追加できます。

3. 型の制約を設ける

インデックスシグネチャを使用すると、オブジェクトのキーや値に対してより細かい制約を設けることもできます。例えば、キーの型をstringから'apple' | 'banana' | 'cherry'といったリテラル型に変更し、値の型をnumberに制限することができます。

interface FruitStock {
  [fruit: 'apple' | 'banana' | 'cherry']: number;
}

const stock: FruitStock = {
  apple: 100,
  banana: 50,
  cherry: 30
};

// エラー: 'orange' は 'apple'、'banana'、'cherry' には含まれません
// stock['orange'] = 20;

この例では、FruitStockというインターフェースに'apple''banana''cherry'のみをキーとして許可しています。そのため、stock['orange'] = 20;とするとコンパイルエラーが発生します。これにより、インデックスシグネチャを使いながらも、許容されるキーを制限することが可能です。

4. 複数のインデックスシグネチャの使い方

TypeScriptでは、インデックスシグネチャを複数指定することもできます。これは、異なる型のキーを使いたい場合に便利です。例えば、数値キーと文字列キーを使って別々の値を格納するケースです。

interface MultiKeyStore {
  [key: string]: string;
  [key: number]: boolean;
}

const store: MultiKeyStore = {
  "item1": "apple",
  2: true,
  "item2": "banana",
  4: false
};

console.log(store);

上記の例では、MultiKeyStoreというインターフェースに文字列型のキーでstring型の値を、数値型のキーでboolean型の値を格納できるようにしています。このように、インデックスシグネチャを複数指定することで、より複雑なデータ構造を表現することができます。

5. 型の拡張とインデックスシグネチャ

インデックスシグネチャは型の拡張にも使用できます。既存の型に新たな動的なプロパティを追加したい場合、インターフェースの拡張を使用します。

interface BasicInfo {
  name: string;
  age: number;
}

interface ExtendedInfo extends BasicInfo {
  [key: string]: string | number;
}

const person: ExtendedInfo = {
  name: "John",
  age: 30,
  address: "123 Main St",
  phoneNumber: "555-1234"
};

console.log(person);

この例では、BasicInfo型を拡張してExtendedInfo型を定義しています。ExtendedInfo型では、nameageに加えて、動的に追加される文字列や数値のプロパティを許可しています。インターフェースの拡張にインデックスシグネチャを組み合わせることで、柔軟かつ型安全にオブジェクトを管理できます。

6. まとめ

TypeScriptのインデックスシグネチャは、オブジェクトのプロパティ名やキーが動的に決まる場合に非常に便利な機能です。インデックスシグネチャを使うことで、キーが事前に分からない場合でも、型安全を保ちながら柔軟にプロパティを追加できます。さらに、インデックスシグネチャを使いこなすことで、型制約を設けたり、拡張性のあるデータ構造を構築したりすることができます。

動的なキーを扱う必要がある場合、インデックスシグネチャはTypeScriptの強力なツールであり、型システムを活用することで、エラーを減らし、より堅牢なコードを書くことができます。