Property 'files' does not exist on type 'EventTarget' error in typescript
Asked Answered
P

14

120

I am trying to access the value of the input file from my ionic 2 application but still I'm facing the issue of property files does not exist on type 'EventTarget'. As it is properly working in js but not in typescript. The code is given below:

  document.getElementById("customimage").onchange= function(e?) {
            var files: any = e.target.files[0]; 
              EXIF.getData(e.target.files[0], function() {
                  alert(EXIF.getTag(this,"GPSLatitude"));
              });
          }

Please help me solve this issue as it is not building my ionic 2 application.

Penza answered 3/4, 2017 at 4:36 Comment(0)
P
81

The e.target property type depends on the element you are returning on getElementById(...). files is a property of input element: https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement

In this case, the TypeScript compiler doesn't know you are returning an input element and we dont have an Event class specific for this. So, you can create one like the following code:

interface HTMLInputEvent extends Event {
    target: HTMLInputElement & EventTarget;
}

document.getElementById("customimage").onchange = function(e?: HTMLInputEvent) {
    let files: any = e.target.files[0]; 
    //...
}
Phina answered 3/4, 2017 at 5:14 Comment(4)
As someone suggested below you may just use: "e: any". I was wondering what are the pros for using the approach offered here?Selfsupport
@Tomer, it's more likely because there is no pros of loosing the type of typescript. Each time you are using "any" you remove the types guards.Endurance
Exactly right. In a nutshell, if you use "any" here, you may as well not use TypeScript at all. That's a bit hyperbolic -- I've been known to use "any" when I'm not in the mood to define a type just for a single function's parameter -- but the logic is consistent; the only reason to use TypeScript at all is to allow the compiler to assist you by preventing you from making type-based mistakes.Vietnamese
I like the suggested approach but I'm not sure regarding the purpose of & EventTarget part. I understand that target: HTMLInputElement adds a property to the extended type Event that's called target and is of type HTMLInputElement. But what do we gain by saying "oh, right, it can also be of another type too...". What am I missing here?Kwapong
U
133

You can cast it as a HTMLInputElement:

document.getElementById("customimage").onchange = function(e: Event) {
    let file = (<HTMLInputElement>e.target).files[0];
    // rest of your code...
}

Update:

You can also use this:

let file = (e.target as HTMLInputElement).files[0];
Uncurl answered 5/7, 2017 at 17:1 Comment(3)
you're writting it in ts?Fucoid
@AliSajid Yes, check this out: blogs.microsoft.co.il/gilf/2013/01/18/…Uncurl
Events are propagating, target could be other elements in different type. Better to use e.currentTarget, which IS a HTMLInputElement.Charie
P
81

The e.target property type depends on the element you are returning on getElementById(...). files is a property of input element: https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement

In this case, the TypeScript compiler doesn't know you are returning an input element and we dont have an Event class specific for this. So, you can create one like the following code:

interface HTMLInputEvent extends Event {
    target: HTMLInputElement & EventTarget;
}

document.getElementById("customimage").onchange = function(e?: HTMLInputEvent) {
    let files: any = e.target.files[0]; 
    //...
}
Phina answered 3/4, 2017 at 5:14 Comment(4)
As someone suggested below you may just use: "e: any". I was wondering what are the pros for using the approach offered here?Selfsupport
@Tomer, it's more likely because there is no pros of loosing the type of typescript. Each time you are using "any" you remove the types guards.Endurance
Exactly right. In a nutshell, if you use "any" here, you may as well not use TypeScript at all. That's a bit hyperbolic -- I've been known to use "any" when I'm not in the mood to define a type just for a single function's parameter -- but the logic is consistent; the only reason to use TypeScript at all is to allow the compiler to assist you by preventing you from making type-based mistakes.Vietnamese
I like the suggested approach but I'm not sure regarding the purpose of & EventTarget part. I understand that target: HTMLInputElement adds a property to the extended type Event that's called target and is of type HTMLInputElement. But what do we gain by saying "oh, right, it can also be of another type too...". What am I missing here?Kwapong
T
66

This is more lines, but I think it's the clearest.

    const onChange = (event: Event) => {
      const target= event.target as HTMLInputElement;
      const file: File = (target.files as FileList)[0];
      /** do something with the file **/
    };

2022 update: Some people have rightly pointed out that the two casts on the second line are unnecessary, this is totally correct and I've revised my answer.

    const onChange = (event: React.ChangeEvent) => {
        const target= event.target as HTMLInputElement;
        const file = target.files[0];
        /** do something with the file **/
    };
Tumult answered 1/2, 2019 at 20:59 Comment(4)
What type would you suggest for the reader.onloadend = ($event: ProgressEvent) => { ... } when I try to access $event.target? The target is of a type that has a property called result but my TsLint complains about the property not being there (due to the type not properly set by me, of course).Kwapong
I mean like in this sample. What is the type of e.target and e.target.result?Kwapong
You dont need to cast the files. When you cast the HTMLInputElement, it automatically inferes the target.files type. Plus, it's dangerous to go around casting everything. The lesser you cast, the better.Doloritas
I surfed at least half of the internet to find this solution. It is quite difficult to explain to other developers why strong typing is necessary in computing. Thank you a lot @Devin ClarkAblative
R
14
const handleFileInput = (event: ChangeEvent) => {
        const target = event.target as HTMLInputElement;
        const file: File = (target.files as FileList)[0];
        /** do something with the file **/
    };

I would change Event to ChangeEvent, however the rest of Devin Clark's answer is great :)

Relation answered 25/11, 2020 at 18:19 Comment(0)
I
7
const onChange => (event: Event): void {
    const input = event.target as HTMLInputElement;

    if (!input.files?.length) {
        return;
    }

    const file = input.files[0];
    console.log(file);
}
Illusionism answered 9/12, 2020 at 10:34 Comment(1)
Please provide an explanation about your answer, stackoverflow.com/help/how-to-answerAzerbaijani
O
5
// use - ChangeEvent<HTMLInputElement>

document.getElementById("customimage").onchange= function(e?: ChangeEvent<HTMLInputElement>) {
            var files: any = e.target.files[0]; 
              EXIF.getData(e.target.files[0], function() {
                  alert(EXIF.getTag(this,"GPSLatitude"));
              });
          }
Ockeghem answered 4/5, 2020 at 18:15 Comment(1)
I think this answer should be accepted. At least it worked for me.Persons
C
4

Based on a few other answers and slight refactoring over time I now commonly cast the ChangeEvent in one line like so:

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  const files = e.target.files;
  if (!files || !files.length) {
    alert("Please select a file!");
  }
}
Chrotoem answered 30/6, 2022 at 0:36 Comment(0)
T
3

I have found that:

<input type="file"  accept="image/*" 
(change)="upload($event)">

and

<ion-input type="file"  accept="image/*" 
(change)="upload($event)"><ion-input>  or (ionChange)

does not handle the event in the same way. Therefore event.target consists of different parameters.

I therefore did not use the ion-input tag, but the normal angular <input> tag with the (change)="upload($event)" trigger.

It worked for me on Ionic 4.

Tavares answered 18/2, 2019 at 9:32 Comment(0)
E
2

Better avoid Type Casting whenever possible. Use e.currentTarget instead of e.target

Ehr answered 10/6, 2021 at 16:52 Comment(0)
L
0

I just come to solved the same probleme, when I use :

e.target.files

It said that target doesnot have files property, so as you said in type script. You can also use :

e.target['files'][0]

It solved my probleme.

Lumenhour answered 8/3, 2022 at 19:38 Comment(0)
S
0

my problem is solved, I am use <any>

if you use useRef, it's also work

Sentience answered 11/12, 2022 at 22:44 Comment(0)
H
0
function getImg(e: Event) {
  
    const target = e.target as HTMLInputElement;
    const files = target?.files;

    if (files) {
        let url = window.URL.createObjectURL(files[0]);
        return url;
    }

}
Henshaw answered 23/7, 2023 at 12:38 Comment(1)
Code only answers carry little value. You should explain what this code does and how it answers the question.Gileadite
S
0

after many iterations, this is what worked for me:

async function upload(e: Event & { currentTarget: EventTarget & HTMLInputElement }) {
    if (!e.currentTarget || !e.currentTarget.files) return;
    const file = e.currentTarget.files[0];
    //...
}

i'm on typescript@^5.1.6, using svelte's on:change={upload} but unsure if that's relevant

Saturant answered 11/8, 2023 at 13:53 Comment(0)
B
0

I solved my problem for my react project by following code.

const handleFileChange = (event: Event | ChangeEvent ) => {
    const target = event.target as HTMLInputElement;
    const selectedFile: File = (target.files as FileList)[0];
    console.log("Selected File:", selectedFile, event);
};
Bombsight answered 19/2 at 14:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.