インデックス型 (index signature)
TypeScriptで、オブジェクトのフィールド名をあえて指定せず、プロパティのみを指定したい場合があります。そのときに使えるのがこのインデックス型(index signature)です。たとえば、プロパティがすべてnumber型であるオブジェクトは次のように型注釈します。
typescriptlet obj: {[K: string]: number;};
typescriptlet obj: {[K: string]: number;};
フィールド名の表現部分が[K: string]です。このKの部分は型変数です。任意の型変数名にできます。Kやkeyにするのが一般的です。stringの部分はフィールド名の型を表します。インデックス型のフィールド名の型はstring、number、symbolのみが指定できます。
インデックス型のオブジェクトであれば、フィールド名が定義されていないプロパティも代入できます。たとえば、インデックス型{ [K: string]: number }には、値がnumber型であれば、aやbなど定義されていないフィールドに代入できます。
typescriptlet obj: {[K: string]: number;};obj = { a: 1, b: 2 }; // OKobj.c = 4; // OKobj["d"] = 5; // OK
typescriptlet obj: {[K: string]: number;};obj = { a: 1, b: 2 }; // OKobj.c = 4; // OKobj["d"] = 5; // OK
コンパイラーオプションのnoUncheckedIndexedAccessを有効にした場合、インデックス型では、プロパティの型は自動的にプロパティに指定した型とundefined型のユニオン型になります。これは、プロパティが存在しないときに、値がundefinedになるのを正確に型で表すためです。
typescriptconst obj: { [K: string]: number } = { a: 1 };const b: number | undefined = obj.b;console.log(b); //=> undefined
typescriptconst obj: { [K: string]: number } = { a: 1 };const b: number | undefined = obj.b;console.log(b); //=> undefined
Record<K, T>を用いたインデックス型#
インデックス型はRecord<K, T>ユーティリティ型を用いても表現できます。次の2つの型注釈は同じ意味になります。
typescriptlet obj1: { [K: string]: number };let obj2: Record<string, number>;
typescriptlet obj1: { [K: string]: number };let obj2: Record<string, number>;