Types error with AxiosResponse and UseQueryResult - reactjs

I am using react query in my typescript project.
export type CarouselData = {
name: string;
body: string;
imgOne: string;
imgTwo: string;
};
export const getCarouselData = async (): Promise<
AxiosResponse<CarouselData[]>
> => {
return await (
await publicAPI.get('/carouselData')
);
};
export const useGetCarouselData = (): UseQueryResult<
Promise<AxiosResponse<CarouselData[]>>
> => {
return useQuery('getCarouselData', getCarouselData);
};
In my component, I am consuming this as follows.
type Item = {
name: string,
body: string,
imgOne: string,
imgTwo: string,
}
export const HomeCarousel: FC = () => {
const {Root} = useStyles();
const result = useGetCarouselData();
console.log(result.data.data); //data.data is giving an error
return (
<Root>
<Carousel<Item[]>>
{result.data.data.map((item, index)=> {
return <CarouselItem key={index} name={item.name} body={item.body} imgOne={item.imgOne} imgTwo={item.imgTwo}/>
})}
</Carousel>
</Root>
)
}
Now, I am getting an error Property 'data' does not exist on type 'Promise<AxiosResponse<CarouselData[], any>>'.ts(2339) that shouldn't be there?
I want to know why this is happening or how to resolve this. : )
Any help is appreciated.

react-query unwraps the Promise, so you'd want: UseQueryResult<AxiosResponse<CarouselData[]>>
Or, you can just use type inference. Leave out the type and let the compiler figure it out :)

Related

is not assignable to type IntrinsicAttributes

I'am working on a next.js project where i pass data from getStaticProps to the main component and when i try to pass it to the children i get an error saying that the data i try to pass are not assignable: here is the code:
the data :
export async function getStaticProps() {
let articlesArray: articleCard[] = []
const data = await getArticlesList().then((response) => {
return response
})
if (data) {
articlesArray.push(...data)
}
return {
props: {
articlesArray
}
}
}
Then i get it in the main component:
export default function Blog(props: { articlesArray: articleCard[] }) {
const articlesList = props.articlesArray
return (
<div className='container'>
<ArticleList articleList={articlesList} />
</div>
)
}
then the component that will use the data:
function ArticleList({articleList}: articleCard[]) {
const [currentPage, setCurrentPage] = useState<number>(1)
const [articlesPerPage] = useState<number>(6)
return (
<h1> rest of the code </h1>
)
}
for info:
the cardArticle type is as follows:
export interface fields {
title: string
slug: string
content: [Object]
excerpt: string
coverImage: [Object]
date: string
author: [Object]
categories: []
}
export interface articleCard extends fields {
id: string
}
the errors:
at ArticleList: Property 'articleList' does not exist on type 'articleCard[]'.
at Blog on the ArticleList component:
Type '{ articleList: articleCard[]; }' is not assignable to type 'IntrinsicAttributes & articleCard[]'.
Property 'articleList' does not exist on type 'IntrinsicAttributes & articleCard[]'.

Argument of type 'never[]' is not assignable to parameter of type 'Comment | (() => Comment)'

I've been for some hours tryin to solve this, I've made the code below using as base another component pretty equal from the same project. What am I doing wrong?
The error is exactly what I've put in title: Argument of type 'never[]' is not assignable to parameter of type 'Comment | (() => Comment)'. I think it's something about the interface or the state above, idk.
import React, { useState, useEffect } from 'react';
import { collection, getDocs } from 'firebase/firestore';
import { db } from '../../services/firebase';
import { CommentListDiv } from './styles';
interface Comment {
email: string;
message: string;
name: string;
}
const CommentList = ({ pokemon }: { pokemon: any }) => {
const [comments, setAllComments] = useState<Comment>([]);
const collectionRef = collection(db, `comments-${pokemon.id}`);
const loadAllComments = async (): Promise<any> => {
await getDocs(collectionRef).then((snapshot) => {
const allComments: any = snapshot.docs.map((doc) => doc.data());
console.log(allComments);
console.log(comments);
setAllComments(allComments);
});
};
useEffect(() => {
loadAllComments();
});
return (
<div>
<CommentListDiv>
<h1>Comments about {pokemon.name}</h1>
<h2>Name: {comments.name}</h2>
<h2>E-Mail: {comments.email}</h2>
<p>
Message:
<br />
{comments.message}
</p>
</CommentListDiv>
</div>
);
};
export default CommentList;
This is the return of both console.logs (the return is correct, the exact entry that I've made and that's showing at Firebase too:
useState<Comment>([]);
This says that the state will contain exactly one Comment, but then you try to pass an array in as the initial value. If the state is supposed to store an array of comments, then do:
useState<Comment[]>([]);

how can i give type in getServerSideProps of Nextjs with typescript?

I'm using NextJs + TypeScript to make a little clone project, but I got a problem with type in getServerSideProps.
As you can see, in getServerSideProps, I am fetching data using with context.query.
But some error message is not fixed and I don't understand why that error appears.
The error message is this.
Type 'string[]' cannot be used as an index type.ts(2538)
Type 'undefined' cannot be used as an index type.ts(2538)
const genre: string | string[] | undefined
How can I fix this type problem?
import Head from "next/head";
import Nav from "../components/Nav/Nav";
import Header from "../components/Header/Header";
import Results from "../components/Results/Results";
import requests from "../utils/requests";
import { GetServerSideProps } from "next";
type HomeProps = {
results: {}[];
};
export default function Home({ results }: HomeProps) {
console.log(results);
return (
<div>
<Results results={results} />
</div>
);
}
export const getServerSideProps: GetServerSideProps = async (context) => {
const genre = context.query.genre
const response = await fetch(
`https://api.themoviedb.org/3${
requests[genre]?.url {/*this is problem line*/}
|| requests.fetchTopRated.url
}`
);
const data = await response.json();
return {
props: { results: data.results },
};
};
You can use like this;
type PageProps = {
isAuthanticated: boolean,
categories?: CategoryType[]
}
export const getServerSideProps: GetServerSideProps<PageProps> = async (context) => {
const _props: PageProps = {
isAuthanticated: auth,
categories: data.results
}
return { props: _props }
};
const Category: NextPage<PageProps> = (props) => {
return(
...
)
};
Since the type of genre can be string or string[] (or undefined), it can not be used to index requests without being narrowed down to string via the use of an if statement:
if (typeof genre === 'string') {
// Typescript now knows it is a string
const response = await fetch(
`https://api.themoviedb.org/3${
requests[genre]?.fetchTopRated.url {/*this is problem line*/}
|| requests.fetchTopRated.url
}`
);
const data = await response.json();
return {
props: { results: data.results },
};
} else if (typeof genre == 'object'){
// handle case where it is an array
} else {
// genre is undefined
}
When you receive params via context, the value could be either string or string[] (or undefined) so you need to cast. It could be a single genre or multiple genres in the URL.
?genre=film or ?genre=film&genre=music
For you case, simply cast as string:
const genre = context.query.genre as string;
UPDATE
As per your comments, the first issue that you raised in the question was actually about casting to string as above.
The second issue, which you should not actually be seeing and must be a TS or module config issue, is related to trying to accessing a key as string by index on your vanilla object exported from "../utils/requests";
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ fetchTrending: { title: string; url: string; }; ...
Your data object has literal key names:
// ../utils/requests
export default {
fetchTrending: {
title: "Trending",
url: /trending/all/week?api_key=${API_KEY}&language=en-US,
},
fetchTopRated: {
title: "Top Rated",
url: /movie/top_rated?api_key=${API_KEY}&language=en-US,
},
};
Rather define the type like this:
export interface IRequest {
[name: string]: {
title: string;
url: string;
};
}
const data: IRequest = {
fetchTrending: {
title: "Trending",
url: `/trending/all/week?api_key=${API_KEY}&language=en-US1`
},
fetchTopRated: {
title: "Top Rated",
url: `/movie/top_rated?api_key=${API_KEY}&language=en-US`
}
};
export default data;
or you could use a Record to have strongly typed keys:
type RequestNames = "fetchTrending" | "fetchTopRated";
export const records: Record<
RequestNames,
{
title: string;
url: string;
}
> = {
fetchTrending: {
title: "Trending",
url: `/trending/all/week?api_key=${API_KEY}&language=en-US1`
},
fetchTopRated: {
title: "Top Rated",
url: `/movie/top_rated?api_key=${API_KEY}&language=en-US`
}
};

React: How to solve: Property 'children' does not exist on type 'IntrinsicAttributes & Props'

I'm trying fetch data from an API and display the data into list of cards in React with typeScript. Since I am new with React in Typescript, not sure how I can solve this error or am I missing something.
This is the error I get:
Type '{ children: string[]; key: number; }' is not assignable to type 'IntrinsicAttributes & Props'.
Property 'children' does not exist on type 'IntrinsicAttributes & Props'.
This is the code:
interface Props {
pokemonItem: PokemonItem;
}
export const PokemonCardList = (props: Props) => {
const { pokemonItem } = props;
const {
id = '',
name = '',
weight = '',
height = '',
abilities = '',
} = pokemonItem;
const [pokemon, setPokemon] = React.useState<PokemonItem[]>([]);
const [loadItems, setLoadItems] = React.useState(API_URL);
const getPokemons = async () => {
setLoading(true);
const response: any = await fetch(loadItems);
const data = await response.json();
setLoadItems(data.next);
setPokemon(data.results[0].name);
setLoading(false);
const getEachPokemon = (result: any) => {
result.forEach(async (element: any) => {
const response = await fetch(
`https:pokeapi.co/api/v2/pokemon/${element.id}`
);
const data = await response.json();
// // setPokemon((currentArrayList) => [...currentArrayList, data]);
pokemon.push(data);
});
};
getEachPokemon(data.results);
await console.log(pokemon);
};
React.useEffect(() => {
return getPokemons();
}, []);
return (
<div>
{pokemon &&
pokemon.map((item, index) => (
<PokemonCard key={index}>
{item.name} {item.height} {item.weight} {item.abilities}
</PokemonCard>
))}
</div>
);
};
Thie pokemonCard component:
interface Props {
pokemonItem: PokemonItem;
}
const PokemonCard = (props: Props) => {
const { pokemonItem } = props;
const {
id = '',
name = '',
weight = '',
height = '',
abilities = '',
} = pokemonItem;
const [imageLoaded, setImageLoaded] = React.useState(false);
const urlImage = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${id}.png?raw=true`;
return (
<div imageLoaded={imageLoaded}>
<div
src={urlImage}
onLoad={() => setImageLoaded(true)}
/>
<div>
Name: {name}
Height: {height}
Weight: {weight}
Abilities: {abilities}
</div>
</div>
);
};
Use PropsWithChildren from react:
import React, {Component, PropsWithChildren} from "react";
interface OwnProps {
foo?: BarComponent;
}
// For class component
class MyComponent extend Component<PropsWithChildren<OwnProps>> {
...
}
// For FC
const MyFunctionComponent: FC<PropsWithChildren<Props>> = ({
children,
}) => (...)
According to your definition of the PokemonCard component, you should be passing the pokemonItem as follow:
<PokemonCard pokemonItem={item} key={item.id} />
I have replaced the key prop as it is not recommended to use indexes as keys (see documentation), you could use the item's id instead. And you need to update the prop interface for the PokemonCard component so that the additional key prop doesn't break the validation:
interface Props {
pokemonItem: PokemonItem;
key: string;
}
Try this (add type for you component):
export const PokemonCardList: React.FC<Props> = (props) => {}
import React from "react";
import Paper, { PaperProps } from "#material-ui/core/Paper";
interface TableEmployeeProps extends PaperProps {
// your props
}
const TableEmployee: React.FC<TableEmployeeProps> = (props) => {
return (
<Paper {...props}> </Paper>
}

Type Children Element is missing properties with Nextjs + React Context with TypeScript

Using Reacts Context with Nextjs and TypeScript is showing a vague error wrapping context around the _app.tsx.
Event though I am passing in the values to the Context Provider it's giving me the error:
"Type '{ children: Element; }' is missing the following properties from type 'ContextProps': capturedPokemons, catchPokemon, releasePokemon"
Here is my _app.tsx
function MyApp({ Component, pageProps }: AppProps) {
return (
<CaughtProvider>
<Component {...pageProps} />
</CaughtProvider>
);
}
Here is the Context:
type PokemonProps = {
number: string;
name: string;
image: string;
};
type ContextProps = {
capturedPokemons: PokemonProps[];
catchPokemon: (newPokemon: PokemonProps[]) => void;
releasePokemon: (id: string) => void;
};
const CaughtContext = createContext<ContextProps>({
capturedPokemons: [],
catchPokemon: () => undefined,
releasePokemon: () => undefined,
});
export const useCaught = () => useContext(CaughtContext);
export const CaughtProvider: React.FC<ContextProps> = ({ children }) => {
const [capturedPokemons, setCapturedPokemons] = useState<any>([]);
const catchPokemon = (newPokemon: PokemonProps[]) => {
if (capturedPokemons.length >= 6) {
alert('You cannot carry any more Pokemon.');
return;
}
const alreadyCaptured = capturedPokemons.some(
(p: PokemonProps) => p.name === newPokemon[0].name
);
if (alreadyCaptured) {
alert('you already have that pokemon');
return;
}
if (window.confirm('Capture Pokemon')) {
setCapturedPokemons([...capturedPokemons, ...newPokemon]);
}
};
return (
<CaughtContext.Provider
value={{ catchPokemon, capturedPokemons, releasePokemon }}>
{children}
</CaughtContext.Provider>
);
};
The app works fine as expected and as I'm aware this is how it's done in plain React/JS without TypeScript.
You need to have a separate type for the CaughtProvider
type CaughtProviderProps = {
children: React.ReactNode
}
and use it as
CaughtProvider: React.FC<CaughtProviderProps>
ContextProps is for your context value so its not right to use it for CaughtProvider . CaughtProvider is just a component which takes the children prop . So its better to have a separate type for it .

Resources