TypeScript で innerText の ts2339 エラーを対処する
TypeScript で HTML DOM 操作していた際に innerText プロパティを参照したところ ts2339 エラーが発生したので、原因と対処方法について紹介します。
やりたいこと
HTML 内の <span class="data">
要素を全部取ってきて、いくつかの要素内のテキストを取得したかったので、以下のようなコードを TypeScript で書きました。
ところが、Property 'innerText' does not exist on type 'Element'. (ts2339)
と TypeScript のエラーがでます。Element
型に innerText
というプロパティはないといわれています。
このエラーの原因の調査と、対処方法について紹介します。
環境
- ブラウザ
- Microsoft Edge 121.0.2277.112
- typescript
- 5.2.2
HTML DOM API の仕様
TypeScript の前に、まず HTML DOM API 自体の仕様を確認しようと思い、MDN で innerText
を調べます。
innerText
はHTMLElement
のプロパティで、ノードとその子孫の「レンダリングされている」テキスト内容を示します。
なるほど、innerText
は HTMLElement
のプロパティなので、HTMLElement
の継承元である Element
は確かに innerText
プロパティはないわけですね。
ここでふと、そもそも querySelectorAll()
が返す型ってなんだっけと思い、こちらも調べます。
生きていない
NodeList
で、指定されたセレクターの 1 つ以上に一致する子孫ノード 1 つに対して 1 つずつのElement
を含みます。
予想通りですが、Element
の NodeList
でした。TypeScript のエラーが言っていることは正しいわけですね…。
なお、蛇足ですが、innerText
は HTMLElement
のプロパティでしたが、innerHTML
は Element
のプロパティなんですね。知りませんでした…。
Element
オブジェクトのinnerHTML
プロパティは、要素内の HTML または XML のマークアップを取得したり設定したりします。
TypeScript の仕様
原因はほぼわかったようなものですが、念のため TypeScript の仕様も確認してみました。
驚きだったのが、私は 3 つ目の仕様のみを期待していたのですが、getElementsByTagName
のような使い方で、引数に HTML や SVG のタグ名のみを渡す場合はそのタグに応じた型の NodeListOf
で返してくれるようです。
実際に試してみましたが、以下の元のコードでは spans
は NodeListOf<Element>
型でしたが、
以下のように querySelectorAll()
の引数をタグ名にしてみると、spans
は NodeListOf<HTMLSpanElement>
型に型推論され、HTMLSpanElement
は HTMLElement
を継承しているので、innerText
プロパティを参照しても冒頭の ts2339 エラーはでなくなりました。
型アサーションで対応
さて、TypeScript で querySelectorAll()
の引数でタグ名を指定した場合は、そのタグに応じた型に型推論がなされることはわかりましたが、今回はタグ名ではなく、クラス名を含めたセレクタ文字列を渡したかったので、型アサーションで ts2339 エラーを回避したいと思います。
または
と型アサーションをつけることで ts2339 エラーはでなくなります。
なお、innerText
プロパティは HTMLElement
のプロパティなので、厳密に NodeListOf<HTMLSpanElement>
としなくても NodeListOf<HTMLElement>
でも問題ありません。
また今回セレクタの全要素が欲しかったので querySelectorAll()
を使用していますが querySelector()
の場合は、
または、
のように型アサーションします。
あとがき
TypeScript で 直に HTML DOM 操作することってそれほど多くないと思うのですが、たまたま実装する機会があって、結果勉強になりました。