readAsDataURL の reader.result の型にArrayBuffer やnullが含まれる理由
readAsDataURLを使った以下のコードがあります。
reader.resultはbase64 エンコーディングされた data: URL の文字列が格納されるはずですが、型はstring | ArrayBuffer | nullになっています。そのため、if分で分岐する処理が必要になっています。
なぜreader.resultの型はstring ではないのでしょうか?
const readFileAsync = async (file: File | Blob): Promise<string> => { return new Promise((resolve, reject) => { const reader = new FileReader() reader.onload = (e) => { if (!(reader.result instanceof ArrayBuffer) && reader.result != null) { resolve(reader.result) } else { reject(new Error("FileReader result is not an ArrayBuffer")) } } reader.onerror = (e) => { reject(e) } reader.readAsDataURL(file) }) }
reader.resultの型がstring | ArrayBuffer | nullになっているのは、FileReaderオブジェクトのreadAsDataURL()メソッドが非同期で実行されるためです。
FileReaderオブジェクトのreadAsDataURL()メソッドは、指定したファイルを非同期に読み込み、その結果をreader.resultに格納します。読み込みが完了するまでに時間がかかるため、reader.resultの型は非同期の結果を受け入れる必要があります。
読み込みが成功した場合、reader.resultはbase64エンコーディングされたdata URLの文字列となります。しかし、読み込みが失敗したり、まだ読み込みが完了していない場合はnullが格納される可能性もあります。
そのため、コード内でif文を使ってreader.resultの型をチェックし、値がstringであるかどうかを判断しています。stringであればresolve()が呼ばれ、結果を返すことができます。ArrayBufferであるかnullである場合は、エラーとしてreject()が呼ばれます。
reader.resultの型がArrayBufferになるケースについて詳しく教えてください。
reader.resultの型がArrayBufferになるケースは、FileReaderオブジェクトがreadAsArrayBuffer()メソッドを使用してデータを読み込んだ場合です。
readAsArrayBuffer()メソッドは、指定したファイルを非同期にバイナリ形式で読み込み、その結果をreader.resultに格納します。
reader.readAsDataURL()メソッドと異なり、readAsArrayBuffer()メソッドではデータをバイナリ形式で読み込むため、reader.resultの値の型はArrayBufferになります。ArrayBufferは、固定長のバイナリデータのバッファを表すオブジェクトです。
したがって、もしreadFileAsync関数の中でreader.readAsArrayBuffer(file)を使用してファイルを読み込むように変更すれば、reader.resultの型は必ずArrayBufferになることが期待されます。
そりゃそうか。
reader.onload = (e) => {}ブロックの時点ではこの後にreader.readAsDataURL()が実行されるかreader.readAsDataURL()が実行されるかわからないから、両方の型を取るのは当然か。
