目次
TypeScriptでHTMLCollectionを扱う際に、以下のようなエラーに遭遇したことはありませんか?
Type 'HTMLCollectionOf<HTMLMetaElement>' can only be iterated through when using the '--downlevelIteration' flag or with a '--target' of 'es2015' or higher.
開発環境では問題なく動作するのに、本番ビルドでだけエラーになる厄介な問題です。この記事では、簡単で確実な解決方法を紹介します。
問題のコード
以下のようなコードでエラーが発生します:
const metas = document.getElementsByTagName('meta')
for (const meta of metas) { // ← ここでエラー
const name = meta.getAttribute('name')
// 処理...
}
エラーメッセージが示すように、HTMLCollectionOf<HTMLElement>
はfor...of
ループで直接反復処理できません。
解決方法
最も簡単で確実な解決方法は、従来のインデックスベースのループに書き換えることです:
const metas = document.getElementsByTagName('meta')
for (let i = 0; i < metas.length; i++) {
const meta = metas[i]
const name = meta.getAttribute('name')
// 処理...
}
修正前後の比較
// ❌ エラーになるコード
for (const meta of metas) {
const np = meta.getAttribute('name') || meta.getAttribute('property')
if (typeof np !== 'string') continue
}
// ✅ 修正後のコード
for (let i = 0; i < metas.length; i++) {
const meta = metas[i]
const np = meta.getAttribute('name') || meta.getAttribute('property')
if (typeof np !== 'string') continue
}
他の解決方法
方法1: Array.fromを使用
const metas = document.getElementsByTagName('meta')
for (const meta of Array.from(metas)) {
// 処理...
}
方法2: スプレッド演算子を使用
const metas = document.getElementsByTagName('meta')
for (const meta of [...metas]) {
// 処理...
}
方法3: Array.prototype.forEachを使用
const metas = document.getElementsByTagName('meta')
Array.prototype.forEach.call(metas, (meta) => {
// 処理...
})
なぜ開発環境では動くのか
開発環境と本番環境でTypeScriptのコンパイル設定が異なるためです:
- 開発環境: より新しいES仕様でコンパイル
- 本番環境: 互換性のためにES5などの古い仕様でコンパイル
この違いにより、HTMLCollectionOf
の反復処理の挙動が変わります。
推奨する解決方法
実際のプロジェクトでは、インデックスベースのループを推奨します:
for (let i = 0; i < collection.length; i++) {
const element = collection[i]
// 処理...
}
理由
- 互換性が高い: どのES仕様でも動作
- パフォーマンス: 配列変換のオーバーヘッドがない
- シンプル: 追加のメソッド呼び出しが不要
- デバッグしやすい: インデックスが分かりやすい
実際の修正例
私のプロジェクトでの実際の修正:
// lib/api.ts での修正
export const getMetaData = async (url: string) => {
const res = await fetch(url)
const text = await res.text()
const doms = new JSDOM(text)
const metas = doms.window.document.getElementsByTagName('meta')
// 修正前: for (const meta of metas)
for (let i = 0; i < metas.length; i++) {
const meta = metas[i]
const np = meta.getAttribute('name') || meta.getAttribute('property')
if (typeof np !== 'string') continue
if (np.match(/title/)) {
// タイトル処理...
}
}
}
まとめ
HTMLCollectionOf
でfor...of
ループエラーが出た場合:
- インデックスベースのループに書き換える(推奨)
- 必要に応じて
Array.from()
で配列に変換 - TypeScript設定の見直しも検討
この修正により、開発環境と本番環境で一貫した動作を保証できます。シンプルで確実な解決方法なので、同じエラーに遭遇した際はぜひ試してみてください。