Как установить объекты File и length в объекте FileList, где файлы также отражаются в объекте FormData?

Можно установить свойство .files элемента <input type="file"> в FileList из, например, другого свойства <input type="file"> element .files или свойства DataTransfer.files. См. Сделать .files устанавливаемым # 2866, Что происходит между загрузкой файла в HTML-форму и отправкой его?.

FileList объект имеет свойство Symbol.iterator, которое мы можем использовать для установки объекта File, который является итерируемым, однако .files .length по-прежнему установлен в 0 и передает <form> <input type="file">, где параметр .files задан с использованием вышеприведенного подхода, дает объект File, имеющий .size, установленный в 0.

Как установить File в FileList и установить .length из FileList на количество установленных файлов, где файлы установлены в FormData() объект?

const input = document.createElement("input");

const form = document.createElement("form");

const [...data] = [
  new File(["a"], "a.txt")
, new File(["b"], "b.txt")
];

input.type = "file";

input.name = "files";

input.multiple = true;
// set `File` objects at `FileList`
input.files[Symbol.iterator] = function*() {
   for (const file of data) {
     yield file
   };
};

form.appendChild(input);

const fd = new FormData(form);

for (const file of input.files) {
  console.log(file); // `File` objects set at `data`
}

for (const [key, prop] of fd) {
  // `"files"`, single `File` object having `lastModified` property
  // set to a time greater than last `File` object within `data`
  // at Chromium 61, only `"files"` at Firefox 57
  console.log(key, prop); 
}

console.log(input.files.length); // 0

Ответ 1

Изменить:

Как доказано OP, в одном из их сути, на самом деле есть способ сделать это...

конструктор DataTransfer (в настоящее время поддерживается только Blink), должен создать изменяемый FileList (chrome в настоящее время всегда возвращает новый FileList, но для нас это не имеет особого значения), доступный через DataTransferItemList.

Если я не ошибаюсь, в настоящее время это единственный метод, способный сделать это, но Firefox, похоже, также имеет ошибку в их реализации Конструктор ClipboardEvent, где тот же самый DataTransferItemList доступен и установлен в режим чтения/записи. Я не уверен в своей интерпретации спецификаций, но считаю, что он не должен быть доступен нормально).

Таким образом, способ, которым guest271314 нашел установку произвольных файлов в FileList, следующий:

const dT = new ClipboardEvent('').clipboardData || // Firefox bug?
  new DataTransfer();                              // specs compliant
dT.items.add(new File(['foo'], 'programmatically_created.txt'));
inp.files = dT.files;
<input type="file" id="inp">