◆ new File([blob], name, option) で Blob を File にできる
◆ コピーになるから大きいファイルの場合に注意

Blob → File

File は Blob を継承していて name とかプロパティが増えたくらいです
なので単純に name プロパティつければ行けるんじゃない? と思ったのですが

async function main() {
const bin = Uint8Array.from([10, 20, 30, 40, 50])
const blob = new Blob([bin], { type: "application/octet-stream" })
blob.name = "file1.bin"

const fd = new FormData()
fd.append("blob-file", blob)
fd.append("message", "123")
fetch("http://localhost/", { method: "POST", body: fd })
}
main()

これのリクエストを見ると

------WebKitFormBoundaryWJK7SxWOvPvAHbAo
Content-Disposition: form-data; name="blob-file"; filename="blob"
Content-Type: application/octet-stream



filename は blob になってます
file1.bin という名前は使われてません

プロパティの有無じゃなくてちゃんと型で判断してそうです
なので ちゃんと Blob を File 型に変換します

async function main() {
const bin = Uint8Array.from([10, 20, 30, 40, 50])
const blob = new Blob([bin], { type: "application/octet-stream" })
const file = new File([blob], "file1.bin", { type: "application/octet-stream" })

const fd = new FormData()
fd.append("blob-file", file)
fd.append("message", "123")
fetch("http://localhost/", { method: "POST", body: fd })
}
main()

------WebKitFormBoundarywujHcsyP3u9Yi6n8
Content-Disposition: form-data; name="blob-file"; filename="file1.bin"
Content-Type: application/octet-stream



ちゃんと file1.bin が設定されました

コピーされる

Blob や File の 1 つ目の引数は ArrayBuffer や Blob の配列を入れるとそのデータがコピーされます
read して Uint8Array で確認するとちゃんと同じものになってます

const blob2u8 = b => {
return new Promise(resolve => {
const r = new FileReader()
r.onload = () => resolve(new Uint8Array(r.result))
r.readAsArrayBuffer(b)
})
}

const blob = new Blob([Uint8Array.from([10, 20, 30])], {})
const file = new File([blob], "", {})

console.log(await blob2u8(blob))
// Uint8Array(3) [10, 20, 30]

console.log(await blob2u8(file))
// Uint8Array(3) [10, 20, 30]

Blob や File はコンストラクタで作成時にコピーされて変更不可のオブジェクトです
元になった ArrayBuffer を変えても Blob や File に影響はしませんが コピーが発生する以上 大きめのファイルなら注意したほうがいいかもです

使いみち

どういうシーンでタイミングで Blob から File に変換する必要があるのか ですがダウンロードしたファイルを POST するときなどに発生します
ローカルファイルなら最初から File で取得できますが

const blob = await fetch(url).then(e => e.blob())

こういう fetch で取得するデータは Blob にしかなりません
POST するときにファイル名を含めたいなら Blob じゃなくて File にしないといけません

追記

FormData を使うなら 3 つ目の引数に filename を設定できました

const bin = Uint8Array.from([10, 20, 30, 40, 50])
const blob = new Blob([bin], { type: "application/octet-stream" })

const fd = new FormData()
fd.append("blob-file", blob, "file1.bin")
fetch("http://localhost/", { method: "POST", body: fd })

------WebKitFormBoundary9GZPDvAB32SvqzEK
Content-Disposition: form-data; name="blob-file"; filename="file1.bin"
Content-Type: application/octet-stream



他に File 型である必要のあるところない思いつきませんし Blob から File への変換自体不要かもしれませんね