Home > Software engineering >  Argument of type '(prev: Phone[]) => Phone[]' is not assignable to parameter of type &#
Argument of type '(prev: Phone[]) => Phone[]' is not assignable to parameter of type &#

Time:08-29

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;
};

CodePudding user response:

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;

CodePudding user response:

Thanks to Nicholas Tower, here is solution to the problem, summed up.

So, bug was in createContext initialization, more specificly type defentition of initial values. Here is already FIXED code.

import { createContext, useState } from 'react';
import { Phone } from '../types/Phone';

type LikedContextInterface = {
  likedGadgets: Phone[];
  setLikedGadgets: (value: Phone[] | ((prev: Phone[]) => Phone[])) => void;
  likedGadgetsID: string[];
  setLikedGadgetsID: (value: string[] | ((prev: string[]) => string[])) => void;
};

export const likedContext = createContext<LikedContextInterface>({
  likedGadgets: [],
  setLikedGadgets: () => {},
  likedGadgetsID: [],
  setLikedGadgetsID: () => {},
});

type Props = {
  children: React.ReactNode;
};

export const LikedContextProvider: React.FC<Props> = ({ children }) => {
  const [likedGadgets, setLikedGadgets] = useState<Phone[]>([]);
  const [likedGadgetsID, setLikedGadgetsID] = useState<string[]>([]);

  return (
    <likedContext.Provider value={
      {
        likedGadgets, setLikedGadgets, likedGadgetsID, setLikedGadgetsID,
      }
    }
    >
      { children }
    </likedContext.Provider>
  );
};

in type of LikedContextInterface I wrongly set type of state-setter functions setLikedGadgets and setArrayOfLiked:

before

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

which meant that it was allowed only to recieve argument of type Phone[]

after

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

now it can recieve either value: Phone[] , or ((prev: Phone[]) => Phone[])) - callback , that with argument of type Phone[], and return Phone[].

also Dispatch<SetStateAction<Phone[]>> wasn't working for me , since type defenition was outside function component.

  • Related