Search code examples
reactjstypescriptuse-state

Argument of type '(prev: Phone[]) => Phone[]' is not assignable to parameter of type 'Phone[]'


So I' m using useState with callback as an argument: setLikedGadgets((prev: Phone[]) => [...prev, info]);

but I recieve errors:

Argument of type '(prev: Phone[]) => Phone[]' is not assignable to parameter of type 'Phone[]'. Type '(prev: Phone[]) => Phone[]' is missing the following properties from type 'Phone[]': pop, push, concat, join, and 28 more.

on the other hand , if I use instead of prev code: setLikedGadgets([...likedGadgets, info]); it all works. But how to make it work in typescript in normal way?

import { useContext } from 'react';
import { likedContext } from '../context/LikedContext';
import { Phone } from '../types/Phone';

export const useLikes = () => {
  const {
    likedGadgets
    arrayOfLiked,
    setLikedGadgets,
    setArrayOfLiked,
  }
    = useContext(likedContext);

  const addToLiked = (info: Phone) => {
    if (arrayOfLiked.includes(info.id)) {
      return;
    }

    if (arrayOfLiked.length === 0) {
      setLikedGadgets([info]);
      setArrayOfLiked([info.id]);
    } else {
      setLikedGadgets((prev: Phone[]) => [...prev, info]);
    }
  };

  return { addToLiked };
};

by the way , type of setLikedGadgets is (value: Phone[]) => void

which I cannot change , because, thats how I defined it during createContext() initialization.

type LikedContextInterface = {
  likedGadgets: Phone[];
  setLikedGadgets: (value: Phone[]) => void;
  arrayOfLiked: string[];
  setArrayOfLiked: (value: string[]) => void;
};

Solution

  • type LikedContextInterface = {
      likedGadgets: Phone[];
      setLikedGadgets: (value: Phone[]) => void;
      arrayOfLiked: string[];
      setArrayOfLiked: (value: string[]) => void;
    };
    

    In this definition, setLikedGadgets is a function that takes in an array of phones. Passing a function to setLikedGadgets violates the type, so typescript shows you an error.

    Based on the way you're using it, it appears that setLikedGadgets is a react state-setter function. That would mean it can either take the new value, or it can take a function which computes the new state from the old state. If you want to preserve that behavior, then that information will need to be included in the type.

    If you want to import the types from react, they are:

    import { Dispatch, SetStateAction } from 'react';
    
    type LikedContextInterface = {
      likedGadgets: Phone[];
      setLikedGadgets: Dispatch<SetStateAction<Phone[]>>;
      arrayOfLiked: string[];
      setArrayOfLiked: (value: string[]) => void; // <--- this may want similar treatment
    };
    

    Or if you want to write it yourself, you could do:

    setLikedGadgets: (value: Phone[] | ((prev: Phone[]) => Phone[])) => void;