zawatech

【Typescript】オブジェクトのプロパティを後から追加する方法

カテゴリ
Typescript
Xこの記事をポストする
この記事をLINEでシェア

最近AtcocderをTypescriptで解いていて、オブジェクトを後から追加するケースが出てきた時に普通に追加しようとしたら

Property 'name' does not exist on type 'Obj'.

のようなエラーが出て追加できませんでした。
以下解決方法を残してきます。

TL;DR

interface Obj {
    [prop: string]: any
}
const obj: Obj = {}
obj.name = 'hoge'   // エラーが出ない

初期化するときに『[prop: string]: any』のプロパティを持つインターフェースを使って初期化することで、後から好きなプロパティを追加することができます。

エラー内容

オブジェクトを作った後に、追加でプロパティを入れたい時に、VSCodeだと↓のようにエラーが出ます。

const John = {
    id: 1,
    age: 20,
}
John.name = 'Jhon Hemingway' // プロパティ 'name' は型 '{ id: number; age: number; }' に存在しません。
// また、条件式でundefinedかどうかを判定しようとしてもエラーになる
if(John.name) {
    console.log('Yes')
}
// (コンパイル時) Property 'name' does not exist on type '{ id: number; age: number; }'.

Typescriptは型を厳密に見るので、初期化したプロパティにないものを追加すると怒られます。

しかし、以下のようにAPIを呼んだときに必須ではないプロパティは何も入っていない時はそもそもオブジェクトの中に入らず渡ってくることもあります。

apiResponse1 = {
 id: 2,
 name: 'Jun',
 email: 'hoge@hoge.com',
}                            // 電話番号は任意項目のため、空の場合はプロパティごと返されない
apiResponse2 = {
 id: 4,
 name: 'Hanako',
 email: 'hanako@huga.jp',
 phone: '01077778888'        // 電話番号がある場合は、phoneを返してくれる
}

また、Atcoderのような限られた時間の中で、途中から「AとBを合計したプロパティも入れておこう」というケースも少なくはありません。そんな時に今回の方法で対処することができます。

対処法

対処法としては、なんでも入るインターフェースを作り、それを型として初期化することで回避できます。

interface Obj {
    [prop: string]: any      // これを記述することで、どんなプロパティでも持てるようになる
}
const John: Obj = {        // Obj型
    id: 1,
    age: 20,
}
John.name = 'Jhon Hemingway'   // エラーにならない!!

Objというインターフェースは、『[prop: string]: any』を記述してあげることでどんなプロパティも持てるようになります。

そしてJohnを初期化するときにそのObjという型で宣言してあげることで、どんなプロパティでも持てる型になるという原理です。

一応公式としてもこの方法を推奨しているようです。
Typescript公式

Xこの記事をポストする
この記事をLINEでシェア
zawa1205

zawa1205

Qiita
GitHub
mail

webフロントエンドエンジニア