1

Hello everyone I'm trying to figure out how to upload a document in React + TypeScript and I have a state with the selected file set up by the onFileChange event listener like so:

onFileChange(event: React.ChangeEvent<HTMLInputElement>) {
    if (event !== null && event.target !== null && event.target.files !== null) {
        this.setState({selectedFile: event.target.files[0]});
    }
};

And so far that works, but when I construct the FormData object it errors out.

if (this.state !== null && this.state.selectedFile !== null) {
        const formData = new FormData();
        formData.append(
            "foo",
            this.state.selectedFile,
            this.state.selectedFile.name
        );
    }

But I'm getting this error:

TS2345: Argument of type 'null' is not assignable to parameter of type 'string | Blob'

I figured I already had checked for nullability for this.state.selectedFile and this.state. Any reason why this isn't working? Am I interpreting this wrong?

5
  • Aside from your question, I note that event.target.files could still have .length == 0. AFAIK, TypeScript's flow-analysis still doesn't consider array lengths. Commented Aug 31, 2021 at 3:59
  • What is the declared type of this.state.selectedFile? Do you have strict nulls on or off? Commented Aug 31, 2021 at 4:00
  • I don't have a declared type for it I initialised my state like so ``` state = { selectedFile: null };``` Commented Aug 31, 2021 at 4:09
  • I do have strict null check turned on Commented Aug 31, 2021 at 4:09
  • 1
    "I initialised my state like so state = { selectedFile: null };" - that's the problem. Give your initial state a better type. Commented Aug 31, 2021 at 4:11

1 Answer 1

1

"I initialized my state like so state = { selectedFile: null };"

Without an explicit type annotation, TypeScript infers the static-type from its initial value, so TypeScript thinks that your selectedFile property can only ever be null.

A solution is to initialize your state with a wider type annotation, like this:

state = {
    selectedFile: null as File | null
};

or like this:

state: { selectedFile: File | null } = {
    selectedFile: null
};

or like this:

type MyStateType = { selectedFile: File | null };

state: MyStateType = {
    selectedFile: null
};

or like this:

interface MyStateType {
    readonly selectedFile: File | null // <-- React state is meant to be immutable so the `readonly` keyword is correct, but you might have issues in the rest of your codebase
}

state: MyStateType = {
    selectedFile: null
};
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.