🧩

[TypeScript] ブラケット記法を使用した際のインデックスシグネチャエラーにハマった

2023/02/10に公開

こんにちは 👋 バヅクリの伊藤です。
バヅクリでは、TypeScript を使用した開発を行っています 😺

今回は、TypeScript でオブジェクトの値へブラケット記法でアクセスした際にでたエラーについて、原因と解決方法、調べたことをまとめました!

エラー内容

type UserType = {
  name: string;
  country: string;
};

const user: UserType = {
  name: "Taro",
  country: "Japan",
};

Object.keys(user).map((key) => {
  console.log(user[key]);
});

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'UserType'. No index signature with a parameter of type 'string' was found on type 'UserType'.

直訳すると...
type 'string' の式は type 'UserType' のインデックスに使用できないため、要素は暗黙的に 'any' タイプを持ちます。 タイプ 'string' のパラメータを持つインデックス署名がタイプ 'UserType' に見つかりませんでした。

console.log 内で使用した key は string 型のため、'UserType'には存在していない。
定義されている key(例でいう name か country)が、保証されていないため any になってしまう。。。ということだと解釈しました。

解決した方法

解決方法がいくつかあったので備忘録として残します

1.  index signature を使用する

エラー文をそのまま検索窓にいれて調べた際に多く出てきたのは、index signatureを使用した方法でした。

type UserType = {
  [K in string]: string;
};

エラーは解消しましたが index signatureは、今回であれば string 型の key を全て許容する為、
取得した値が、undefined とのユニオン型になります。

つまり、以下の様なコードを書いた際に、型エラーは起こらない。

type UserType = {
  [K in string]: string;
};

const user: UserType = {
  name: "Taro",
  country: "Japan",
};

console.log(user["age"]); // undefined

使用する際は、この特徴を理解しておく必要があると思いました 📝

2.Record を使用する

Record はUtility Typesと呼ばれる TypeScript の便利な型の 1 つ。

先ほどの index signature と同様に、string 型の key を受け入れることもできる

type UserType = Record<string, string>;

また、key をユニオン型で指定することも可能

type UserType = Record<"name" | "country", string>;

const user: UserType = {
  name: "Taro",
  country: "Japan",
};

console.log(user["age"]);

Element implicitly has an 'any' type because expression of type '"age"' can't be used to index type 'UserType'. Property 'age' does not exist on type 'UserType'.

この場合は、きちんと型エラーが起き, UserTypeに'age'がないことを知らせてくれました

3. 条件分岐を使用する

key の値が定義した key であるか確認することでエラーは解消される為、条件分岐を使用する方法も 1 つの方法です。

Object.keys(user).map((key) => {
  if (key === "name" || key === "country") {
    console.log(user[key]);
  }
});

key に入る値は"name" | "country"となるのでエラーが解消されました

4. Object.entries()を使用する

Object.entries() メソッドは、引数に与えたオブジェクトが所有する、文字列をキーとした列挙可能なプロパティの組 [key, value] からなる配列を返します。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/entries

for (const [key, value] of Object.entries(user)) {
  console.log(value);
}

そもそもブラケット記法で値を取得する必要もないため、エラーは解消されました

5. keyof を使用する

keyofは、オブジェクトのプロパティ名を型として返してくれる演算子

type UserType = {
  name: string;
  country: string;
};

const user: UserType = {
  name: "Taro",
  country: "Japan",
};

const key: keyof UserType = "name";

console.log(user[key]);

まとめ

今回は、TypeScriptのエラーと向き合い 様々なアプローチ方法を知ることができました📝
今後もエラーにハマった際は積極的に記事に残していこうと思います^^

最後に

バヅクリでは Rails エンジニアを募集しています!
カジュアル面談等も受け付けておりますので、ご興味ある方は下記リンクから是非お問い合わせください ✉️

https://herp.careers/v1/buzzkuri/wCQFGVkQS3Xa

https://buzzkuri.co.jp/recruit

バヅクリテックブログ

Discussion