Typescript(インデックスシグネチャ)

はじめに

今回の記事はインデックスシグネチャ(インデックス型)についてです。前回記事のインターフェースなども利用した記事になっていますのでインターフェースについてよくわからないと感じる方は前回記事
Typescript(インターフェース) - 駆け足エンジニアの記録
参照で宜しくお願いします。

インデックスシグネチャの定義

[key:T]:U・・・これをオブジェクトリテラルで挟むことで、このオブジェクトについては型Tの全てのキー(プロパティ名)は、型Uの値を持たなければならない。
実際の使用例で確認しましょう。

interface MovietheatreSeatingAssigment {
  [seatNUmber: string]: string;
}
const users : MovietheatreSeatingAssigment = {
  k12: "Max",
  k13: "Green",
  k14: "Jon",
};

このケースは映画館の座席の割当についてのオブジェクトです。インターフェースなどで、オブジェクトから1つ1つキーと値の型を定義するのはあまりに面倒です。インデックスシグネチャを使うことで、オブジェクトがより多くのキーを含む可能性があることをTypescriptに伝える事ができます。

インデックスシグネチャの注意点,ユースケース

①キーの型はstring型かnumber型

先程はキーの型がstringでしたがnumber型も可能です。

interface Ranking {
  [rank: number]: string;
}
const ranking: Ranking = {
  1: "Mikasa Ackermann",
  2: "Reiner Brown",
  3: "Bertolt Hoover",
};

余談ですが、オブジェクトのキーは文字列という制約があります。今回のケースではキーはnumber型となっていますが、オブジェクトのキーをnumber型で設定したとしても文字列で自動変換されます。以下はjavascriptのコードです。

const obj = {
  0: 'zero',
  1: 'one,
};
console.log(Object.keys(obj));//(2) ["0", "1"]
②キーの型が同じシグネチャを重複することはできない。

プロパティ名が異なる場合でも、その型が等しければエラーが起きます。

interface Ranking {
  [rank: number]: string;
  [rankgai:number]:string//エラー(number インデックス シグネチャが重複しています。)
}

キーの型を変えればエラーが出ませんでした。

interface Ranking {
  [rank: number]: string;
  [rankgai: string]: string;
}
const ranking: Ranking = {
  1: "Mikasa Ackermann",
  2: "Reiner Brown",
  3: "Bertolt Hoover",
  "104期生": "Armin Harlert",
};
value(値)の型は揃える

インデックスシグネチャが重複する場合、キーの型は異なる必要があったのに対し、valueの型は揃える必要があります。(直前のコード参照)
またインデックスシグネチャを利用するケースは以下のようなことも可能です。ここでもvalueの型は揃える必要があります。

interface obj {
  belongs: string;
  [key: string]: string;
} //valueの型はstring

const person1: obj = {
  belongs: "tyousaheidan",
  name: "Eren Jaeger",
  birthdata: "3/30",
};
④readonlyとの共存

インデックスのシグネチャをreadonlyとしてマークすることもできます。

interface Ranking {
  readonly [rank: number]: string;
}
const ranking: Ranking = {
  1: "Mikasa Ackermann",
  2: "Reiner Brown",
  3: "Bertolt Hoover",
};
ranking[0] = "Eren Jaeger";
//エラー(型 'Ranking' のインデックス シグネチャは、読み取りのみを許可します。)

余談

オブジェクトのプロパティを動的に生成するcomputed property namesを使うと型推論はインデックス型となります。以下のコードをコピーし、vscodeなどのエディタ上で型推論を見てみてください。

let i = 0;
const hokage = {
  [`${++i}代目火影`]: "千手柱間",
  [`${++i}代目火影`]: "千手扉間",
  [`${++i}代目火影`]: "猿飛ヒルゼン",
  [`${++i}代目火影`]: "波風ミナト",
};
console.log(hokage);//1代目火影: "千手柱間"
//2代目火影: "千手扉間"
//3代目火影: "猿飛ヒルゼン"
//4代目火影: "波風ミナト"