メインコンテンツまでスキップ

インデックス型 (index signature)

TypeScriptで、オブジェクトのフィールド名をあえて指定せず、プロパティのみを指定したい場合があります。そのときに使えるのがこのインデックス型(index signature)です。たとえば、プロパティがすべてnumber型であるオブジェクトは次のように型注釈します。

ts
let obj: {
[K: string]: number;
};
ts
let obj: {
[K: string]: number;
};

フィールド名の表現部分が[K: string]です。このKの部分は型変数です。任意の型変数名にできます。Kkeyにするのが一般的です。stringの部分はフィールド名の型を表します。インデックス型のフィールド名の型はstringnumbersymbolのみが指定できます。

インデックス型のオブジェクトであれば、フィールド名が定義されていないプロパティも代入できます。たとえば、インデックス型{ [K: string]: number }には、値がnumber型であれば、abなど定義されていないフィールドに代入できます。

ts
let obj: {
[K: string]: number;
};
 
obj = { a: 1, b: 2 }; // OK
obj.c = 4; // OK
obj["d"] = 5; // OK
ts
let obj: {
[K: string]: number;
};
 
obj = { a: 1, b: 2 }; // OK
obj.c = 4; // OK
obj["d"] = 5; // OK

コンパイラーオプションのnoUncheckedIndexedAccessを有効にした場合、インデックス型では、プロパティの型は自動的にプロパティに指定した型とundefined型のユニオン型になります。これは、プロパティが存在しないときに、値がundefinedになるのを正確に型で表すためです。

ts
const obj: { [K: string]: number } = { a: 1 };
const b: number | undefined = obj.b;
console.log(b);
undefined
ts
const obj: { [K: string]: number } = { a: 1 };
const b: number | undefined = obj.b;
console.log(b);
undefined

📄️ noUncheckedIndexedAccess

インデックス型のプロパティや配列要素を参照したときundefinedのチェックを必須にする

Record<K, T>を用いたインデックス型

インデックス型はRecord<K, T>ユーティリティ型を用いても表現できます。次の2つの型注釈は同じ意味になります。

ts
let obj1: { [K: string]: number };
let obj2: Record<string, number>;
ts
let obj1: { [K: string]: number };
let obj2: Record<string, number>;

📄️ Record<Keys, Type>

キー・バリューからオブジェクト型を作る

関連情報

📄️ Mapped Types

インデックス型では設定時はどのようなキーも自由に設定できてしまい、アクセス時は毎回undefinedかどうかの型チェックが必要です。入力の形式が決まっているのであればMapped Typesの使用を検討できます。