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()
が実行されるかわからないから、両方の型を取るのは当然か。