rohitmi0023
rohitmi0023

Reputation: 119

Type error while uploading file using formData

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

Answers (2)

sanister
sanister

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

Sijmen
Sijmen

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

Related Questions