Help us understand the problem. What is going on with this article?

TypeScriptの型記法「オブジェクトリテラル 」と「インデックスシグネチャ」を理解する

TypeScriptの型記法、「オブジェクトリテラル」「インデックスシグネチャ」について、まとめます。

「オブジェクトリテラル」も「インデックスシグネチャ」も、あまり聞き慣れない言葉で、雰囲気で理解した気になっていませんか?

私は、なっていました。

私の場合、この記法に遭遇するたびに「これって、なんだっけ?」ってなることが多いです。

自分の理解のために、ここにまとめておきたいと思います。

誰かの理解の助けになれば幸いです。

初見殺しな「オブジェクトリテラル」と「インデックスシグネチャ」

例えば、以下のコードにおいて

let obj: {
    [key: string]: string // インデックスシグネチャ
} // オブジェクトリテラル

変数objの型が、何を意味しているか理解できますでしょうか。
私には、初見殺しすぎて、さっぱりわからず「???」となりました。

この型の意味は、「変数objは複数のkeyを含む可能性があり、そのすべてのstring型のkeyは、string型の値をもつ」となります。

以下のコードにおいて、Errorの箇所では、idにnumber型の値を入れているのでエラーとなります。

let obj: {
    [key: string]: string // インデックスシグネチャ
} // オブジェクトリテラル

// OK
obj = {
    id: "123"
    token: "hogetoken"
    name: "fuganame"
}

// Error
// Type 'number' is not assignable to type 'string'.
obj = {
    id: 123
    token: "hogetoken"
    name: "fuganame"
} 

オブジェクトリテラルとは

let obj: {
    id: string
    token: string
    name: string
} // オブジェクトリテラル

このように中括弧({})を用いて、オブジェクトの型を定義する記法のことを指します。
オブジェクトは、ハッシュテーブルの一種で、キーと値の組みを持ちます。
TypeScriptでは、多くの場合、オブジェクトの型は「クラス」を用いて定義されます。

しかし、用途によってはクラスを定義せずに、即席の型定義を記述する方が便利な場合があります。
その際に用いられるのが「オブジェクトリテラル」です。
「オブジェクトリテラル」は、匿名のオブジェクト型を宣言したい場合に用いられます。
(例えばJavaScriptからTypeScriptへの移行期に、"とりあえず"の型を定義したい場合など)

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

let obj: {
    // [key: T]: U
    [key: string]: string // インデックスシグネチャ
}

インデックスシグネチャは、角括弧([])を用いて「[key: T]: U」という構文で記述されます。
これは「オブジェクトが、複数のkey(型T)を含む可能性があること」を示します。
そして、「すべてのkey(型T)は型Uの値を持つこと」も示します。
オブジェクトのキーと値の型を抽象化して記述することができます。

備考

例えば、idだけnumber型で、その他のパラメータはstringの場合、以下のように書けるのかなと思ったのですが、これはエラーになります。

let obj: {
    id: number // エラー
    [key: string]: string
}

// Property 'id' of type 'number' is not assignable to string index type 'string'.
// Type '{ id: number; token: string; name: string; }' is not assignable to type 
// '{ [key: string]: string; id: number; }'. Property 'id' is incompatible with 
// index signature. Type 'number' is not assignable to type 'string'.

obj = {
    id: 123
    token: "hogetoken"
    name: "fuganame"
} 

keyがstringの場合は、stringの値を持つと宣言してしまっているので、

    [key: string]: string

idをnumber型だと定義すると矛盾が発生してしまうためです。

    id: number

[追記] 以下のように型交差記法を用いてもエラーが発生します。
(親切な方、教えていただいてありがとうございます)

// エラー
const obj: { [key: string]: string } & { id: number } = {

  id: 123,

  token: "hogetoken",

  name: "fuganame"

};

よって、この場合はおとなしく、インデックスシグネチャを用いないで書きましょう。

let obj: {
    id: number
    token: string
    name: string
} // オブジェクトリテラル

まとめ

・オブジェクトリテラル({})は、オブジェクトの型を即席で定義するために用いられる。
・インデックスシグネチャ([key: T]: U)は、オブジェクトが、複数のkey(型T)を含む可能性があり値はU型になることを示している。

結論としては、オブジェクトリテラルもインデックスシグネチャもクセが強いので、あまり用いたくないですが、そうは言っても現場ではすでにオブジェクトリテラルやインデックスシグネチャを使用している箇所については、コードを読むために理解しておきたいと思います。

[追記]「オブジェクトリテラル」と「オブジェクト型リテラル」の違いについて

コメント欄にて、下記のご指摘を頂きました。
ありがとうございます。

細かい点ですが、「オブジェクトリテラル」はオブジェクト値を構築する記法のことで、 JavaScript/TypeScript に共通しています。この記事で扱っている、オブジェクトの型を記述する TypeScript 特有の記法は「オブジェクト型リテラル」です

const obj: { n: number } = { n: 42 };
//         ^^^^^^^^^^^^^   ^^^^^^^^^---- オブジェクトリテラル
//               `---------------------- オブジェクト型リテラル

「オブジェクトリテラル」と「オブジェクト型リテラル」の違いについて、理解しました。
この違いはちゃんと理解しておく必要があると感じましたので引用させていただきます。

karamage
モバイルアプリ開発が得意。「My感謝日記」など、人の心を豊かにするアプリを個人開発。TV番組でも紹介され累計20万DL突破。「エンジニアの心を整える技術」著者。Freelance Software Engineer
https://twitter.com/kara_mage
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした