⌨️
TypeScriptでHTMLFormElementを使うときはFormData APIを使うと文字列でValueを取得できる
TypeScriptだと文字列でインデックスのアクセスがうまく行かないケースがある
TypeScriptでフォームの値を取得する際にはHTMLFormElement
型が利用されます。しかしながら、この型には文字列インデックスのシグネチャがないため、以下のようにするとエラーが発生します。
const formElement = document.querySelector('form') as HTMLFormElement;
const value = formElement['inputName']; // Error!
// 特に文字列シグネチャを配列か何かで持っていて、走査したいとき困る
// JSではドット記法による動的な参照は許されていないため
// 動的なプロパティ参照にはブラケット記法を使わなくてはならない
const form = event.currentTarget as HTMLFormElement;
const entry = names.map(id => {
const elem = form.elements;
return elem[name].value // Error!
})
エラーメッセージは次のようになります。
Element implicitly has an 'any' type because index expression is not of type 'number'.
これは文字列インデックスにアクセスできないことが原因です。これはHTMLFormElement
型定義の制限なので、避けようがありません。
FormData APIを使おう
しかしながら、FormData
コンストラクターを使うことでこの問題は簡単に回避できます。
const formElement = document.querySelector('form');
const formData = new FormData(formElement);
formData.get('inputName'); // 文字列インデックスでアクセス OK
FormData
オブジェクトはgetメソッドを介して文字列インデックスに対応しているので、こちらを利用することで文字列キーによる値参照が可能です。
結論として、フォームデータを取得する場合はなるべくFormData
APIを利用することをおすすめします。ネイティブDOM APIよりも扱いやすく、名前付き要素へのアクセスにも柔軟に対応できます。
Discussion
調べてみると、decode-formdataというものもあるようでした。ちょっとデモで使ってみました。
コメントありがとうございます。decode-formdata のモジュールを見てきたのですが、こちらは内部的にDom APIを使っているシンプルなラッパーのようですね。
このモジュールでも、Dom APIを使った結果、複雑な実装になっていると言えると思います。今回の記事ではそれをしなくて済むという話になるかなと思いますので、比較対象、あるいは別の解決策の提示としては不適切に感じます。