Home > other >  TypeScript will not let me use prevState in setState
TypeScript will not let me use prevState in setState

Time:09-23

I am learning TypeScipt and I have already managed to come to a dead end and TS won't let me go any further. So I have defined my interfaces as below:

export interface Test {
  id: number;
  date: Date;
  location: string;
  elements?: Element[];
}

export interface Element {
  id: string;
  name: string;
  referenceFrom: number | string;
  referenceTo: number | string;
  result: number | string;
}

I am then using one of the interfaces for below useState hook:

const [currentTest, setCurrentTest] = useState<Test | null>(null);

And at one point I am trying to use setCurrentTest and the prevState inside of it, however TypeScript won't let me do that and I am getting below error:

Argument of type '(prev: Test | null) => { elements: any[]; id?: number | undefined; date?: Date | undefined; location?: string | undefined; }' is not assignable to parameter of type 'SetStateAction<Test | null>'.
  Type '(prev: Test | null) => { elements: any[]; id?: number | undefined; date?: Date | undefined; location?: string | undefined; }' is not assignable to type '(prevState: Test | null) => Test | null'.
    Call signature return types '{ elements: any[]; id?: number | undefined; date?: Date | undefined; location?: string | undefined; }' and 'Test | null' are incompatible.
      The types of 'id' are incompatible between these types.
        Type 'number | undefined' is not assignable to type 'number'.
          Type 'undefined' is not assignable to type 'number'.ts(2345)

The function that I am using this setCurrentTest in looks like that:

  const handleSubmitForm = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const { id, name } = results;
    const referenceFrom = Number(results.referenceFrom);
    const referenceTo = Number(results.referenceTo);
    const result = Number(results.result);
    if (
      id &&
      name &&
      referenceFrom > 0 &&
      referenceTo > 0 &&
      referenceFrom < referenceTo &&
      result > 0
    ) {
      setCurrentTest((prev) => ({...prev, elements: [...prev.elements, { id, name, referenceFrom, referenceTo, result }] }));
    }
  };

What I understand from this is that the optional null in the Test | null is causing this issue. Also in the interface Element there is this optional elements? which is also causing the issue because it can also be undefined.

So how can I escape this?

CodePudding user response:

If you can't add an initial state to avoid having the null, you can make a validation so it only tries to spread the previous state if it's not null. Like this:

setCurrentTest((prev: any) => {
    if (prev) {
        return {...prev, elements: [...prev.elements, {id, name, referenceFrom, referenceTo, result}]};
    }
    return {elements: [{id, name, referenceFrom, referenceTo, result}]};
});
  • Related