0

I want to create an object which follows the following interface

interface FileList {
  getter File? item(unsigned long index);
  readonly attribute unsigned long length;
};

Eventually, I want to assign that object to the files property of input type=file HTML element

The code I have written so far is

let file1 = new File(["foo"],"foo.txt");
    let fl:FileList = {
      item: function(index){
        file1;
      },
      length: 1
    } as FileList;
...
imageInputNE.files = fl ;

But I am getting error TypeError: Failed to set the 'files' property on 'HTMLInputElement': The provided value is not of type 'FileList'.

I tried creating a typescript class as well but that doesn't work either

class MyFileList{
  file:File;
  length=1;
  constructor(file:File){
    this.file = file;
  }

  item(index):File|null {
    return this.file;
  }

}

...
let file1 = new File(["foo"],"foo.txt");
    let fl:MyFileList = new MyFileList(file1);
imageInputNE.files = fl ;

How could I create an object of type FileList?

Manu Chadha
  • 15,555
  • 19
  • 91
  • 184

1 Answers1

0

You don't have everything that satisfies the standard FileList.

If you press F12 on .files, you'll go to the standard lib.dom.d.ts file, which will show:

files: FileList | null;

Tracking FileList from there will show:

interface File extends Blob {
    readonly lastModified: number;
    readonly name: string;
}

declare var File: {
    prototype: File;
    new(fileBits: BlobPart[], fileName: string, options?: FilePropertyBag): File;
};

interface FileList {
    readonly length: number;
    item(index: number): File | null;
    [index: number]: File;
}

declare var FileList: {
    prototype: FileList;
    new(): FileList;
};

Not just is it too complex to achieve all above, but also I think the property in reality (ignoring TypeScript for a little bit) is read only.

The property is what the user selected from their own computer. It doesn't make sense security-wise that you'd select files by yourself from their computer.

Of course you can always cast the objects you have to any and try yourself to see what happens in runtime.

If the purpose of this that you have some other part of the UI which displays what files are being used, and you want that to show the extra information, I suggest that you modify the part that uses input.files, and make it use your other stuff as well, instead of trying to manipulate the property itself.

Meligy
  • 35,654
  • 11
  • 85
  • 109
  • Thanks. Actually, I am trying to unit test a function which gets called when `change` event is triggered by the `input`. An `Event` object is passed to my function which has `target.files`. As I am unit testing, I don't have the real files so I am trying to make up some data for it – Manu Chadha Jan 17 '19 at 19:49
  • Could you please suggest how I may do this? This might give you some background but all I can test at the moment is that the function is called but I am unable to test that the function works correctly - https://stackoverflow.com/questions/54202209/how-to-trigger-input-onchange-from-angular-spec – Manu Chadha Jan 17 '19 at 19:50
  • I'd suggest you just change the function to take the `files` array. I answered there. – Meligy Jan 17 '19 at 20:18