Motomichi Works Blog

モトミチワークスブログです。その日学習したことについて書いている日記みたいなものです。

TypeScript 学習日記 その0002 キーが未確定なobjectにデータを追加する方法について考える

参考にさせていただいたページ

はじめに

注意して使用しましょう。

「キーが未確定なobjectを先に作って後からデータを追加する」という処理が本当に必要なのかよく考える必要があると思います。

できるだけ先にキーを決めて、データの追加はその型に沿って追加するのが良いと思います。

良くない例

以下のコードでは「キーが未確定なobjectにデータを追加する方法」を使用していますが、良くない例です。

参考にさせていただいた「TypeScriptの型入門 - Qiita」のインデックスシグネチャの項にあるように、以下の例ではMyObj型の定義が曖昧になってしまい、TypeScriptの良さが活かせていません。

    // MyObj型を定義
    type MyObj = {
      [key: string]: number // ここでnumberだけにしているのが良くない
    }

    // 変数myObjをMyObj型で定義
    const myObj: MyObj = {}

    // データを追加できる
    myObj['keyNameA'] = 0
    myObj['keyNameB'] = 1

    // 変数keyに'example'を代入
    const key: string = 'example'

    // myObj.exampleは存在しないキーなので、変数myVariableにはundefinedが入る
    const myVariable = myObj[key]

    // 実際にはmyVariableはundefinedだが、この後の処理でnumberとして型推論がされるので不具合の元になってしまう
    console.log(myVariable) // undefined

少し改善する

以下のように改善できます。

    // MyObj型を定義
    type MyObj = {
      [key: string]: number | undefined // ここでnumber | undefinedにしておくと、myVariableが後の処理で正しく型推論される
    }

「キーが未確定なobjectを先に作って後からデータを追加する」という処理が本当に必要なのか考える

以下のようにできるのであれば、より安全です。

    // MyObj型を定義
    type MyObj = {
      keyNameA: number
      keyNameB: number
    }

    // 変数myObjをMyObj型で定義
    const myObj: MyObj = {
      keyNameA: 0,
      keyNameB: 1,
    }

    // 変数keyに'example'を代入
    const key: string = 'example'

    // MyObj型が予め厳格に定義できているため、ここでコンパイルエラーになり、不具合が未然に防げる
    const myVariable = myObj[key]

    // この後の処理も安心
    console.log(myVariable)

結局のところ

上記した「良くない例」のように [key: string]を使用したり、[index: number]を使用することで、objectのキーやarrayのインデックスを抽象的にすることができますが、使用方法を誤ると型推論が正しく行われなくなってしまいます。

「キーが未確定なobjectを先に作って後からデータを追加する」という処理が本当に必要なのか、それが有効な方法なのかをよく考える必要があると思います。

型推論が正しく行われるように書きましょう。