TypeScriptでDOM操作を行う際、querySelectorAll
は非常に便利なメソッドです。特定のセレクターにマッチするすべての要素を一括で取得できるため、複数の要素に対して同じ処理を行う際によく利用されます。しかし、TypeScriptの型システムでは、querySelectorAll
で取得した要素は汎用的な型(NodeListOf<Element>
)であり、厳密な型安全性を保つためには工夫が必要です。本記事では、querySelectorAll
で取得した複数のDOM要素を型安全にループ処理するための方法を解説します。
`querySelectorAll`とは?
querySelectorAll
は、指定されたCSSセレクタに一致するすべてのDOM要素を取得するためのメソッドです。このメソッドを使うと、複数の要素を効率よく一度に取得でき、返されるのはNodeList
オブジェクトです。例えば、特定のクラス名を持つ要素や特定のタグ名を持つ要素を簡単に取得することができます。
基本的な使い方
querySelectorAll
の基本的な使用例は以下の通りです:
const elements = document.querySelectorAll('.my-class');
この例では、クラス名が「my-class」のすべての要素がelements
に格納されます。querySelectorAll
はすべての一致する要素をNodeList
として返し、これをループ処理して各要素に対して操作を行うことができます。
返される`NodeList`の特徴
querySelectorAll
が返すNodeList
は「ライブコレクション」ではなく静的なリストです。つまり、ページ上でDOMが変更されても、取得したNodeList
はその後のDOMの変更を反映しません。この特徴を理解した上で、必要な要素にアクセスし、適切に処理することが重要です。
TypeScriptでの型の問題
TypeScriptを使ってquerySelectorAll
を利用する際、取得される要素の型に関していくつかの問題があります。querySelectorAll
はDOM要素をまとめて返しますが、TypeScriptの型システムでは、そのすべての要素が同じ型であるとは限りません。
汎用的な型で返される
querySelectorAll
の返り値は、TypeScriptではNodeListOf<Element>
という型です。このElement
型は、すべてのDOM要素を包括する汎用的な型であり、div
やa
、span
などの具体的なHTML要素に絞り込まれていません。したがって、TypeScriptの型安全性を活かして開発を進めるためには、このままでは不十分です。
型安全性が損なわれる可能性
汎用的なElement
型では、各要素が持つ固有のプロパティやメソッドを直接利用できません。例えば、input
要素であることを期待してvalue
プロパティにアクセスしようとすると、TypeScriptはエラーを投げます。
const elements = document.querySelectorAll('input');
elements.forEach(element => {
console.log(element.value); // エラー: Property 'value' does not exist on type 'Element'.
});
このように、Element
型では汎用的すぎて、特定の要素に固有の操作を行う場合に型エラーが発生します。これを解消するためには、取得した要素を適切にキャストして、型安全に処理する必要があります。
型安全なループ処理の必要性
TypeScriptでquerySelectorAll
を使ってDOM要素を取得した際、型安全にループ処理を行うことは非常に重要です。型安全な処理を行わないと、開発中にエラーが見逃されたり、実行時に不具合が発生する可能性があります。
開発中の予期しないエラーを防ぐ
JavaScriptでは、DOM要素に直接アクセスし操作することが一般的ですが、TypeScriptでは型が厳密にチェックされるため、事前に問題を防ぐことが可能です。型安全でない処理を行うと、意図しないエラーがコンパイル時に発生せず、実行時に初めて問題が明らかになることがあります。
const elements = document.querySelectorAll('a');
elements.forEach(element => {
console.log(element.href); // TypeScriptではエラーが検出されない
});
このコードは一見問題なさそうに見えますが、element
の型はElement
であり、TypeScriptの型システムではhref
プロパティが存在するとは限りません。これが原因で、実行時にエラーが発生する可能性があります。
将来のメンテナンス性を向上させる
型安全にコードを書くことで、将来的にコードを他の開発者が修正・拡張する際の理解が容易になり、メンテナンス性が向上します。型が明確に定義されていると、どのようなデータがどのように扱われているのかが明確になり、予期せぬバグやエラーを未然に防げます。
具体的な要素への操作を正確に行うため
DOM操作では、要素によって使用できるプロパティやメソッドが異なります。例えば、input
要素のvalue
や、a
要素のhref
など、特定の要素に対して適切なプロパティやメソッドを操作する際、型安全であればその要素に固有のプロパティを正確に操作することができます。TypeScriptを使用することで、これらの操作が正確かつ安全に行われることを保証します。
`forEach`を使った基本的なループ処理
querySelectorAll
で取得した複数のDOM要素を処理する際、最も基本的でよく使われる方法の一つが、forEach
メソッドを用いたループ処理です。querySelectorAll
はNodeList
オブジェクトを返すため、このオブジェクトに対して直接forEach
を使用して、各要素にアクセスすることができます。
基本的な`forEach`によるループ処理
forEach
は、NodeList
内の各要素に対して順番に処理を実行するために使用されます。以下は、クラス名「my-class」を持つすべての要素を取得し、それぞれの要素に対して処理を行う基本的な例です。
const elements = document.querySelectorAll('.my-class');
elements.forEach((element) => {
console.log(element.textContent); // 各要素のテキスト内容をコンソールに表示
});
この例では、クラス名「my-class」を持つすべての要素が取得され、forEach
によって順番にelement.textContent
がコンソールに出力されます。この処理は非常にシンプルであり、DOM操作の基本的な手法としてよく使用されます。
型安全性の問題
しかし、ここで注意すべき点は、querySelectorAll
で取得したelement
の型がElement
となっているため、厳密にはテキストを持たない可能性のある要素に対してもtextContent
プロパティにアクセスしようとするリスクがあることです。特定の要素(例えば、input
やa
)に対して固有の操作を行いたい場合、このままでは型安全とは言えません。
const links = document.querySelectorAll('a');
links.forEach((link) => {
console.log(link.href); // 直接`href`にアクセスすると型エラーになる可能性
});
このコードは、すべてのa
タグに対してhref
プロパティを参照しようとしていますが、TypeScriptはElement
型であるため、href
の存在を保証しません。この問題を解消するためには、後のセクションで紹介するキャストや型ガードを使用して、安全に型を指定する必要があります。
`as`を使ったキャスト処理
TypeScriptでquerySelectorAll
を使って取得したDOM要素を、特定の型にキャスト(型変換)することで、型安全な操作を実現できます。as
キーワードを使ってキャストすることで、TypeScriptの型システムに対して「この要素は特定の型である」と明示的に伝えることができます。これにより、特定の要素に固有のプロパティやメソッドに安全にアクセスできるようになります。
キャストの基本的な使い方
as
を使うことで、取得したDOM要素を特定の型に変換できます。例えば、input
要素を取得し、そのvalue
プロパティにアクセスする場合、以下のように記述します。
const inputs = document.querySelectorAll('input');
inputs.forEach((input) => {
const inputElement = input as HTMLInputElement;
console.log(inputElement.value); // 型エラーが発生しない
});
このコードでは、input
要素をHTMLInputElement
にキャストしています。これにより、value
プロパティが存在することをTypeScriptが認識し、エラーなくアクセスできるようになります。
キャストが必要な理由
querySelectorAll
で取得した要素は、すべてElement
型として扱われますが、Element
型には多くのHTML要素特有のプロパティ(value
やhref
など)が存在しません。TypeScriptの型システムでは、これらのプロパティに直接アクセスしようとすると型エラーが発生します。キャストすることで、これらの特定のプロパティを利用できる型に変換し、型安全な処理を行うことができます。
複数の要素に対するキャストの使用例
複数の異なる要素に対しても、適切にキャストを行うことで、それぞれのプロパティに安全にアクセスできます。例えば、a
タグのhref
やimg
タグのsrc
プロパティにアクセスする場合、以下のようにキャストします。
const links = document.querySelectorAll('a');
links.forEach((link) => {
const linkElement = link as HTMLAnchorElement;
console.log(linkElement.href); // `href`に安全にアクセス
});
const images = document.querySelectorAll('img');
images.forEach((img) => {
const imgElement = img as HTMLImageElement;
console.log(imgElement.src); // `src`に安全にアクセス
});
このようにキャストを使うことで、TypeScriptが型エラーを出さず、要素の特定のプロパティに安全にアクセスできるようになります。ただし、キャストは開発者が型を保証するための手段であり、実際には誤った型にキャストしないように注意が必要です。
型ガードを使った安全な処理
as
によるキャストは便利ですが、常に適切な型が与えられる保証がない場合、実行時エラーが発生するリスクがあります。そこで、TypeScriptでより安全にDOM要素を処理するために「型ガード」を使う方法があります。型ガードを用いることで、要素の型を実行時に確実に確認し、正しいプロパティやメソッドにアクセスできるようにします。
型ガードとは?
型ガードとは、実行時に特定の型かどうかを確認する方法です。これにより、特定の要素に固有のプロパティにアクセスする際に、正しい型であることを保証できます。例えば、input
要素かどうかを確認してからvalue
プロパティにアクセスすることで、より安全なコードを実現できます。
型ガードの使用例
以下の例では、querySelectorAll
で取得したDOM要素がHTMLInputElement
かどうかを確認し、安全にvalue
プロパティにアクセスしています。
const elements = document.querySelectorAll('input');
elements.forEach((element) => {
if (element instanceof HTMLInputElement) {
console.log(element.value); // 型が確実にHTMLInputElementであることを保証
} else {
console.log('Not an input element');
}
});
このコードでは、instanceof
演算子を使って、element
がHTMLInputElement
であるかどうかをチェックしています。型ガードを使用することで、特定の要素に固有のプロパティに対して型安全にアクセスできることが保証されます。
他の型ガードのパターン
型ガードは他の要素にも適用できます。例えば、a
タグのhref
にアクセスする場合や、button
タグのdisabled
プロパティにアクセスする場合にも、同様の方法で安全に処理できます。
const elements = document.querySelectorAll('a, button');
elements.forEach((element) => {
if (element instanceof HTMLAnchorElement) {
console.log(element.href); // `HTMLAnchorElement`であることを確認してから`href`にアクセス
} else if (element instanceof HTMLButtonElement) {
console.log(element.disabled); // `HTMLButtonElement`であることを確認してから`disabled`にアクセス
} else {
console.log('Unknown element type');
}
});
このように、型ガードを使って要素の型を確認することで、実行時エラーを回避しつつ、型安全な操作を行うことができます。
型ガードを使うメリット
型ガードを使うことで、次のような利点があります:
- 実行時エラーを防ぐ:適切な型であることを確認してからプロパティにアクセスするため、予期しないエラーを防止できます。
- コードの読みやすさが向上:条件分岐によってどの型にアクセスしているかが明示され、コードの可読性が高まります。
- 複数の型に対応可能:複数の要素に対して型チェックを行い、それぞれの要素に適した操作を行うことができます。
このように、型ガードを用いることで、querySelectorAll
で取得したDOM要素に対して、より堅牢で型安全な操作が可能になります。
`Array.from`を使った型の明確化
querySelectorAll
が返すNodeList
は、forEach
などのメソッドが使えるものの、Array
のような便利なメソッド(例えば、map
やfilter
)は使用できません。そこで、Array.from
を使用することで、NodeList
をArray
に変換し、より多彩な操作を行えるようになります。さらに、この変換によって型を明確に指定することも可能となり、より型安全な処理が実現できます。
`Array.from`を使った基本的な使い方
Array.from
は、配列のような構造(NodeList
など)をArray
に変換するためのメソッドです。以下の例では、querySelectorAll
で取得した要素をArray
に変換し、map
メソッドを使って各要素のテキストを抽出します。
const elements = Array.from(document.querySelectorAll('.my-class'));
const textContents = elements.map((element) => element.textContent);
console.log(textContents); // すべての要素のテキスト内容を配列で取得
この例では、querySelectorAll
で取得したNodeList
をArray.from
を使って配列に変換し、map
メソッドを使って各要素のテキストコンテンツを配列として取得しています。Array
に変換することで、map
やfilter
などの便利なメソッドを使えるようになります。
型の明確化
Array.from
を使うとき、ジェネリクスを活用することで、要素の型を明確に指定できます。たとえば、HTMLAnchorElement
のみを対象とした処理を行う場合、以下のように型を指定します。
const links = Array.from(document.querySelectorAll('a')) as HTMLAnchorElement[];
links.forEach((link) => {
console.log(link.href); // 型安全に`href`にアクセス
});
この例では、querySelectorAll('a')
で取得したすべてのa
要素をHTMLAnchorElement[]
型として配列に変換しています。これにより、TypeScriptはlinks
配列の各要素がHTMLAnchorElement
であることを認識し、href
プロパティに安全にアクセスできるようになります。
複数の要素を明確に扱う例
同様に、複数の異なる要素に対してもArray.from
を使って型を明確にすることができます。例えば、button
とa
タグの混合リストを処理する場合、以下のように実装できます。
const elements = Array.from(document.querySelectorAll('a, button')) as (HTMLAnchorElement | HTMLButtonElement)[];
elements.forEach((element) => {
if (element instanceof HTMLAnchorElement) {
console.log(element.href); // `a`タグの場合
} else if (element instanceof HTMLButtonElement) {
console.log(element.disabled); // `button`タグの場合
}
});
この例では、a
タグとbutton
タグの両方を配列に変換し、それぞれに対応するプロパティ(href
とdisabled
)に安全にアクセスしています。
メリットと応用
Array.from
を使うメリットは以下の通りです:
- 配列操作の豊富なメソッド:配列として変換することで、
map
やfilter
、reduce
などの高機能なメソッドを活用できる。 - 型安全性の向上:ジェネリクスを使って型を明示することで、要素のプロパティやメソッドに型安全にアクセスできる。
- 柔軟な要素操作:複数の異なる要素に対しても、一度に安全かつ効率的に処理が可能。
Array.from
を使うことで、型安全性を維持しながら、より効率的にDOM要素を操作できるようになります。
ジェネリックを活用した型安全な処理
TypeScriptの強力な機能の一つに「ジェネリック」があります。ジェネリックを使うことで、汎用的なコードを型安全に記述でき、querySelectorAll
で取得したDOM要素を特定の型に適合させて処理することが可能になります。ジェネリックを適切に活用すれば、異なる要素や属性に対しても型安全な操作が行えるようになります。
ジェネリックの基本的な使い方
TypeScriptのジェネリックを活用することで、関数やクラスに汎用的な型を指定し、異なる型に対応することができます。これをDOM操作に応用することで、複数の型のDOM要素を柔軟かつ型安全に扱うことができます。
例えば、次のようにジェネリックを用いたquerySelectorAll
のラッパー関数を作成することができます。
function getElements<T extends Element>(selector: string): NodeListOf<T> {
return document.querySelectorAll<T>(selector);
}
この関数では、セレクタに一致する要素を汎用的な型で取得できるようにしています。これを使用すると、特定の要素型を指定して型安全な操作が可能です。
const links = getElements<HTMLAnchorElement>('a');
links.forEach(link => {
console.log(link.href); // `HTMLAnchorElement`として型安全にアクセス
});
このようにジェネリックを使用することで、querySelectorAll
で取得した要素に特定の型を指定でき、適切なプロパティやメソッドに安全にアクセスできるようになります。
ジェネリックを使った型安全なループ処理
次に、ジェネリックを活用して、異なるDOM要素を処理する汎用的な関数を作成してみましょう。例えば、a
タグとbutton
タグに対してそれぞれの固有プロパティにアクセスできる関数を作成します。
function processElements<T extends Element>(elements: NodeListOf<T>, callback: (element: T) => void): void {
elements.forEach(callback);
}
const links = document.querySelectorAll<HTMLAnchorElement>('a');
processElements(links, (link) => {
console.log(link.href); // `HTMLAnchorElement`として処理
});
const buttons = document.querySelectorAll<HTMLButtonElement>('button');
processElements(buttons, (button) => {
console.log(button.disabled); // `HTMLButtonElement`として処理
});
この関数では、NodeListOf<T>
に対してジェネリック型T
を使用しており、任意の要素に対応することができます。コールバック関数の引数element
は、T
の型を持つため、特定の要素に対するプロパティに型安全にアクセスできます。
型の継承による高度なジェネリックの活用
さらに、DOM要素の型を継承することで、より柔軟な型安全な処理を行うことも可能です。例えば、次のようにT
をHTMLAnchorElement
またはHTMLButtonElement
に限定した処理を行うことができます。
function handleElements<T extends HTMLAnchorElement | HTMLButtonElement>(elements: NodeListOf<T>) {
elements.forEach((element) => {
if (element instanceof HTMLAnchorElement) {
console.log(element.href); // `HTMLAnchorElement`の場合
} else if (element instanceof HTMLButtonElement) {
console.log(element.disabled); // `HTMLButtonElement`の場合
}
});
}
const mixedElements = document.querySelectorAll('a, button');
handleElements(mixedElements as NodeListOf<HTMLAnchorElement | HTMLButtonElement>);
この例では、T
の型をHTMLAnchorElement
とHTMLButtonElement
に限定することで、複数の型に対応した処理を型安全に行っています。
ジェネリックを使うメリット
ジェネリックを使うことには次のような利点があります:
- 柔軟性と再利用性:一度定義すれば、異なる型の要素に対しても同じロジックを再利用できます。
- 型安全性の向上:コード内で明示的なキャストを避け、型の安全性を保ったまま汎用的な処理が行えます。
- エラーの減少:特定の要素に固有のプロパティやメソッドへのアクセスにおいて、型チェックが行われるため、実行時エラーを減らすことができます。
このように、ジェネリックを活用することで、複数のDOM要素に対して型安全かつ効率的に操作を行うことが可能になります。
エラーハンドリングとデバッグ方法
DOM操作中、特にquerySelectorAll
を使った要素の取得や操作を行う際には、予期しないエラーが発生する可能性があります。TypeScriptの型システムによって多くのエラーはコンパイル時に防げますが、実行時に起こるエラーを考慮して適切なエラーハンドリングを行うことが重要です。ここでは、querySelectorAll
によるDOM操作でのエラーを防ぐ方法や、デバッグに役立つテクニックについて説明します。
エラーハンドリングの基本
querySelectorAll
で取得した要素が存在しない場合や、期待していた型と異なる要素が取得される場合には、エラーハンドリングを行うことが重要です。以下のように、DOM要素が存在するかどうかを確認し、存在しない場合に適切なエラーメッセージを出すようにしましょう。
const elements = document.querySelectorAll('.my-class');
if (elements.length === 0) {
console.error('指定された要素が見つかりませんでした。');
} else {
elements.forEach(element => {
console.log(element.textContent);
});
}
このコードでは、まずquerySelectorAll
で取得した要素が空であるかどうかをチェックし、空であればエラーメッセージをコンソールに表示しています。これにより、空の結果に対して無意味な操作を行うことを防げます。
実行時エラーを防ぐための型ガード
先述した型ガードを利用することで、取得した要素が期待する型であるかどうかをチェックし、型が違う場合にエラーを回避できます。これにより、実行時に想定外の型エラーが発生するリスクを低減できます。
const buttons = document.querySelectorAll('button');
buttons.forEach(button => {
if (button instanceof HTMLButtonElement) {
console.log(button.disabled); // 型が正しい場合のみアクセス
} else {
console.error('この要素はボタンではありません。');
}
});
この例では、instanceof
を使ってボタン要素かどうかを確認し、型が違う場合はエラーメッセージを出力するようにしています。
try-catchでの例外処理
TypeScriptでは、実行時に発生する予期しない例外をキャッチするためにtry-catch
ブロックを使用することができます。これにより、例外が発生してもアプリケーションがクラッシュせずに適切な対処ができるようになります。
try {
const links = document.querySelectorAll('a');
links.forEach(link => {
if (!(link instanceof HTMLAnchorElement)) {
throw new Error('リンク要素ではありません。');
}
console.log(link.href);
});
} catch (error) {
console.error('エラーが発生しました: ', error);
}
この例では、try-catch
ブロック内で要素の型をチェックし、想定外の型であった場合に例外を投げてエラーメッセージを表示します。これにより、エラーが発生しても処理を継続させることが可能です。
デバッグのポイント
DOM操作のデバッグには、ブラウザの開発者ツールが非常に役立ちます。以下は、デバッグを効率化するためのいくつかのテクニックです:
- コンソールログの活用:
console.log
やconsole.error
を活用して、取得した要素や変数の状態を確認しながらデバッグを進めます。例えば、要素の内容や、querySelectorAll
で返されたNodeList
の長さを確認します。
const elements = document.querySelectorAll('.my-class');
console.log('取得した要素数:', elements.length);
- ブラウザ開発者ツールのDOMインスペクタ:ChromeやFirefoxなどのブラウザには、DOMの構造を視覚的に確認できる開発者ツールが備わっています。要素が正しく取得されているか、またはCSSセレクタが適切に機能しているかを確認する際に有用です。
- ブレークポイントの設定:JavaScriptのコード実行中にブレークポイントを設定し、変数の状態やDOMの状況をステップごとに確認できます。これにより、どのタイミングでエラーが発生しているのかを特定するのが容易になります。
エラーハンドリングのベストプラクティス
- 予期しない入力やDOMの変更に対処する:ユーザーの操作や外部のスクリプトによってDOMが予期しない形に変わる可能性があるため、常に存在確認や型チェックを行うことが重要です。
- 適切なエラーメッセージを表示する:エラーメッセージを具体的にすることで、後からのデバッグやメンテナンスが容易になります。
- 例外を無視しない:例外が発生した場合は、常にログに残し、必要に応じてアラートを出すなどの対応を取ることが推奨されます。
エラーハンドリングとデバッグを適切に行うことで、querySelectorAll
を使ったDOM操作がより安全で安定したものになります。
実践演習:`querySelectorAll`を用いたリストの処理
ここまで紹介してきた技術を踏まえて、querySelectorAll
を使って実際のリストアイテムを操作する具体的な例を見ていきます。この演習では、複数のリストアイテムを取得し、それぞれのアイテムに対して異なる操作を実行します。さらに、型安全性を確保しながら効率的にDOM要素を処理します。
リストアイテムの取得と操作
以下のHTMLがあると仮定します。これをもとに、querySelectorAll
を使ってすべてのリストアイテムを取得し、各リストに対して型安全に操作を行います。
<ul>
<li class="item">アイテム1</li>
<li class="item">アイテム2</li>
<li class="item">アイテム3</li>
</ul>
このリストに対して、querySelectorAll
を使ってすべてのli
要素を取得し、各アイテムのテキストを変更します。
const listItems = document.querySelectorAll('li.item');
listItems.forEach((item) => {
const liElement = item as HTMLLIElement;
liElement.textContent = '更新されたアイテム: ' + liElement.textContent;
console.log(liElement.textContent); // 各アイテムの更新後のテキストをコンソールに出力
});
ここでは、querySelectorAll
でクラスitem
を持つli
要素を取得し、それぞれに対してtextContent
を更新しています。as HTMLLIElement
を使って型を明示的にキャストすることで、TypeScriptの型システムが各要素に安全にアクセスできることを保証しています。
ボタンのクリックイベントとの連携
次に、リストアイテムにボタンを追加し、そのボタンをクリックした際にリストアイテムを削除する処理を追加します。この例では、querySelectorAll
でリストアイテム内のすべてのボタンを取得し、クリックイベントを追加して処理を行います。
<ul>
<li class="item">アイテム1 <button class="delete-btn">削除</button></li>
<li class="item">アイテム2 <button class="delete-btn">削除</button></li>
<li class="item">アイテム3 <button class="delete-btn">削除</button></li>
</ul>
const deleteButtons = document.querySelectorAll('button.delete-btn');
deleteButtons.forEach((button) => {
button.addEventListener('click', (event) => {
const buttonElement = event.target as HTMLButtonElement;
const liElement = buttonElement.closest('li');
if (liElement) {
liElement.remove(); // リストアイテムを削除
console.log('アイテムが削除されました:', liElement.textContent);
}
});
});
このコードでは、まずquerySelectorAll
でクラスdelete-btn
を持つすべてのボタンを取得し、各ボタンに対してclick
イベントリスナーを追加しています。ボタンがクリックされた際に、closest
メソッドを使って親のli
要素を取得し、remove
メソッドでその要素を削除しています。event.target
はHTMLButtonElement
として型キャストすることで、型安全な処理が保証されています。
リストアイテムのインデックスを取得する
また、リストアイテムをループ処理する際に、各アイテムのインデックスを取得するケースもよくあります。これを実現するには、forEach
の第2引数を使います。
listItems.forEach((item, index) => {
const liElement = item as HTMLLIElement;
liElement.textContent = `アイテム${index + 1}: ${liElement.textContent}`;
console.log(`アイテム${index + 1}が更新されました:`, liElement.textContent);
});
このコードでは、forEach
の第2引数でインデックスを取得し、各リストアイテムのテキストにそのインデックス番号を付加しています。これにより、アイテムの順序を反映した処理を行うことができます。
フィルターを使ったリストアイテムの選択
最後に、Array.from
を使ってNodeList
を配列に変換し、特定の条件に一致する要素だけを操作する方法を紹介します。例えば、アイテムのテキストに「2」を含むリストアイテムだけを操作するケースを見てみましょう。
const filteredItems = Array.from(document.querySelectorAll('li.item'))
.filter((item) => item.textContent?.includes('2'));
filteredItems.forEach((item) => {
const liElement = item as HTMLLIElement;
liElement.style.color = 'red'; // アイテムの色を赤に変更
console.log('条件に一致したアイテム:', liElement.textContent);
});
この例では、Array.from
を使ってNodeList
を配列に変換し、その後filter
メソッドを使って、テキストに「2」を含むリストアイテムだけを選択しています。選択された要素に対して色を変更し、コンソールに結果を表示しています。
まとめ
実践的な例を通して、querySelectorAll
を使った複数のリストアイテムの操作方法を学びました。TypeScriptの型安全性を維持しながら、DOM要素に対して柔軟に操作を行うことができるようになります。要素の取得、イベント処理、インデックスの取得、そして条件に基づいたフィルタリングなど、さまざまな操作を組み合わせることで、効率的かつ堅牢なコードが書けるようになります。
まとめ
本記事では、TypeScriptでquerySelectorAll
を使って複数のDOM要素を型安全にループ処理する方法について解説しました。型の問題点から始まり、forEach
やキャスト、型ガード、Array.from
、ジェネリックを使ったより高度な処理方法、エラーハンドリングまで幅広くカバーしました。これらの技術を駆使することで、実行時エラーを減らし、メンテナンス性の高いコードを作成できるようになります。
コメント