Reputation: 119
The error message that I receive in the value
part of formData.append(key, value);
:
Argument of type 'unknown' is not assignable to parameter of type 'string | Blob'. Type '{}' is missing the following properties from type 'Blob': size, type, arrayBuffer, slice, and 2 more.
Code
const uploadSubtitle = async e => {
e.preventDefault();
const file = fileInput.current.files[0];
const res = await Axios.get(`/api/movies/${currentMovie.movieId}/subtitles?user=${user.id}`);
const { url, fields } = res.data;
const newUrl = `https://${url.split('/')[3]}.s3.amazonaws.com`;
const formData = new FormData();
const formArray = Object.entries({ ...fields, file });
formArray.forEach(([key, value]) => {
formData.append(key, value);
});
//... further code
};
<form onSubmit={uploadSubtitle}>
<input type='file' name='subtitle' ref={fileInput} accept='.srt' />
<button onClick={uploadSubtitle}>Upload</button>
</form>
Additional details
console.log(file)
gives
File
{name: "Trainspotting-English.srt", lastModified: 1587840529000,
lastModifiedDate: Sun Apr 26 2020 00:18:49 GMT+0530 (India Standard Time),
webkitRelativePath: "", size: 103040, …}
lastModified: 1587840529000 lastModifiedDate: Sun Apr 26 2020 00:18:49 GMT+0530 (India Standard Time)
{} name: "Trainspotting-English.srt" size: 103040
type: "application/x-subrip" webkitRelativePath: "" __proto__: File
console.log(typeof file)
gives
object
Upvotes: 6
Views: 16998
Reputation: 430
I had File data as { name: '', type: '', uri: ''} which was giving the error: Argument of type 'FileData' is not assignable to parameter of type String or Blob
So I did the following:
form.append('file', value as {} as Blob); TS stopped complaining.
Upvotes: 0
Reputation: 506
It all comes down to the unknown type of res
, introduced here:
const res = await Axios.get(`/api/movies/${currentMovie.movieId}/subtitles?user=${user.id}`);
res
is any
, which makes fields
type any
, which in turn makes formArray
be of type [string, unknown][]
, thus value
is unknown
, which causes the error.
To solve this problem at the source, we can use a generic type on the Axios.get
method like so:
const res = await Axios.get<{url :string, fields: {[key:string]:string}}>(`/api/movies/xxx/subtitles?user=xxx`);
This will make res
be of type {url :string, fields: {[key:string]:string}}
. This causes fields
to be of type {[key:string]:string}
.
Unfortunately the spread operator does not infer the right types. The code {...fields, file}
resolves to type {file: File}
, which is not really helpful. So let's hint formArray
:
const formArray : [string, string|File][] = Object.entries({...fields, file});
Now value
will be of type string|File
.
Full example:
function App() {
let fileInput = useRef<HTMLInputElement>(null);
const uploadSubtitle = async (e: React.FormEvent) => {
e.preventDefault();
const file = fileInput.current!.files![0];
const res = await Axios.get<{ url: string, fields: { [key: string]: string } }>(`/api/movies/xxx/subtitles?user=xxx`);
const {url, fields} = res.data;
const formData = new FormData();
const formArray: [string, string | File][] = Object.entries({...fields, file});
formArray.forEach(([key, value]) => {
formData.append(key, value);
});
};
return <form onSubmit={uploadSubtitle}>
<input type='file' name='subtitle' ref={fileInput} accept='.srt'/>
<button type="submit">Upload</button>
</form>
}
This is all rather a lot of work for something that can be fixed by changing the problematic line to:
formData.append(key, value as Blob);
Adding the as Blob
won't change the compiled JS but will make the typescript compiler stop complaining.
Upvotes: 5