Basically, I have a search page component which displays the search results of the query that the user typed in the input field.
This is the file.
"use client";
import { useSearchParams } from "next/navigation";
import useFetch from "../hooks/useFetch";
import ProductCard from "@/components/ProductCard";
const SearchPage = () => {
const search = useSearchParams();
const searchQuery = search ? search?.get("q") : null;
const encodedSearchQuery = encodeURI(searchQuery || "");
const { data } = useFetch(
`/products?populate*=&filters[title][$contains]=${encodedSearchQuery}`
);
console.log(data);
return (
<div>
<div>
{/* {data?.map((product) => (
<ProductCard key={product.id} products={product} />
))} */}
</div>
</div>
);
};
export default SearchPage;
I am using a global hook useFetch for it.
I am able to see the filtered data in the console as well.
Productcard component is basically for structure and it takes a prop called products
I tried mapping with the commented out code but it shows me these errors.
This is useFetch.tsx
In this snippet, I have a utility function called fetchData that is responsible for making API requests. It uses Axios to make the request and includes an authorization header.
"use client";
import { useState, useEffect } from "react";
import { fetchData } from "@/app/utils/api";
const useFetch = (endpoint: string) => {
const [data, setData] = useState(null);
useEffect(() => {
const fetchDataFromApi = async () => {
try {
const res = await fetchData(endpoint);
setData(res);
} catch (error) {
console.error("Error fetching data:", error);
}
};
fetchDataFromApi();
}, [endpoint]);
return { data };
};
export default useFetch;
Property ‘map’ does not exist on type ‘never’.
Parameter ‘product’ implicitly has an ‘any’ type.
I actually saw someone do it exactly the same way but with Javascript.
I am using typescript, I am new to it. How should I do it with typescript?
I can show more components related to it if someone wants to see that.
Any help is appreciated
2
Answers
You need to declare and pass the expected type (e.g: Product) to TypeScript and make the
useFetch
generic (taking in the type of expected data returned):Now TypeScript knows
data
‘s type (Product[]
).Notes:
Product
can also be atype
.error
andloading
fromuseFetch
, which would allow you to handle the error and loading states in your components, but that’s outside the scope of this questionSo the issue you’re having is connected with TypeScript part of it. When fetching the data I believe you are getting back an
any
from thefetchData
and the type yourres
isany
.But the core issue is your
useState
declaration. You’re initializing it tonull
, so when you try to accessdata?.anyMethod()
it is going to benever
, and it will gives out "Property ‘map’ does not exist on type ‘never’".You can use Generics with
useState
(which itself is a generic function) to let TypeScript know what kind of data it is going to store, in your case you can create a type for your product:and hand it over to
useState
generic in your case as I guess you’re expecting an array of products, it should be:But as your
useFetch
function itself is reusable one I’d advice you to make it a generic one itself, so you can pass the type when calling it and expect to receive it. You can achieve this doing so:And after when calling it you just pass the type: