I'm trying to figure out what Typescript type a change event is used in an Angular project.
The code is something simple like this:
file-upload.component.html
<input type="file" (change)="onChange($event)"/>
file-upload.ts
public onChange(event: Event): void {
if (event.target.files && event.target.files.length) {
const [file] = event.target.files;
console.log(file);
}
}
Typing the event as Event gives me the following Typescript linting error:
Property 'files' does not exist on type 'EventTarget'
What should I be typing this if not Event?
the files should be a accessible thru the event.srcElement.files property.
It is an event. But you're going to have to cast the const you're using as an HTMLInputElement.
public onChange(event: Event): void {
if ((event.target as HTMLInputElement).files && (event.target as HTMLInputElement).files.length) {
const [file] = event.target.files;
}
}
The only other way is going to be to suppress the error with tsignore. In react, flow, they have a type SyntheticEvent that you can type this particular case as to get around it but angular doesn't have a real equivalent.
public onChange(event: Event): void {
const input = event.target as HTMLInputElement;
if (!input.files?.length) {
return;
}
const file = input.files[0];
console.log(file);
}
You just have to write this before doing anything with your event:
if (!(event.target instanceof HTMLInputElement)) return;
Typescript will then know that your event.target is an instance of HTMLInputElement and it will stop yelling at you.
You could specify property target of Event to be an HTMLInputElement using an intersection type as the typehint of event.
public onChange(event: Event & { target: HTMLInputElement }): void {
if (event.target.files && event.target.files.length) {
const [file] = event.target.files;
console.log(file);
}
}
An intersection type combines multiple types into one. This allows you to add together existing types to get a single type that has all the features you need.
https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#intersection-types
The accepted answer throws two errors in my compiler: (event.target as HTMLInputElement).files is possibly 'null' and Type 'FileList' must have a '[Symbol.iterator]()' method that returns an iterator.
This works for me:
const target = event.target as HTMLInputElement;
if (target.files && target.files.length) {
const file = target.files[0];
}