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

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

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[]'.

properly typing props in a Next.js page [duplicate]

This question already has an answer here:
How to type a page component with props in Next.js?
(1 answer)
Closed 5 months ago.
I have a fairly straight forward SSR-generated Next.js page. My typing is not correct somewhere along the path here, and the linter is complaining.
export interface ProposalTag {
id: number;
name: string;
hex: string;
color: string;
}
export async function getProposalTags(): Promise<ProposalTag[]> {
// query for response
const tags = response?.data?.proposal_tags.map((tag: ProposalTag) => {
return {
id: tag.id,
name: tag.name,
hex: tag.hex,
color: tag.color,
};
});
return tags;
}
export const getServerSideProps: GetServerSideProps = async context => {
const proposalTags: ProposalTag[] = await getProposalTags();
return {
props: {
proposalTags,
},
};
};
const Proposal: NextPage = ({ proposalTags }) => { /* code */ }
In this particular case, the linter is complaining with the following:
Property 'proposalTags' does not exist on type '{}'
I'm not entirely sure what I can do to please the typescript interpreter/linter here
NextPage is a generic type with optional generic parameters, and the first one is the prop types for the component:
const Proposal: NextPage<{
proposalTags: ProposalTag[];
}> = ({ proposalTags }) => { /* code */ }

Home and GetServerSideProps type error in Nextjs with Typescript

I'm struggling with getting my first Nextjs project with Typescript and next-firebase-auth package. I want to call the API in getserversideprops, and return the value to the main component, in this case, the index page.
Here is how it looks right now
import {
AuthAction,
useAuthUser,
withAuthUser,
withAuthUserTokenSSR,
} from "next-firebase-auth";
import FullPageLoader from "../components/layout/FullPageLoader";
import SignUp from './signup/index';
import {useEffect} from 'react';
import {useRouter} from 'next/router';
import { NextPage } from "next";
type PageProps = {
profile: boolean | {
username: string,
name: string,
surname: string
}
}
const Home: NextPage<PageProps> = (props) => {
const AuthUser = useAuthUser()
const router = useRouter()
useEffect(() => {
if (props.profile) {
router.push(`/advisor/${AuthUser.id}/profile`)
}
}, [AuthUser.id, props.profile, router])
return (
<>
<SignUp />
</>
);
};
export const getServerSideProps = withAuthUserTokenSSR({
whenUnauthed: AuthAction.REDIRECT_TO_LOGIN,
})(async ({AuthUser}:any) => {
const token = await AuthUser.getIdToken()
const response = await fetch(`htpp://localhost:3001/profile/${AuthUser.id}/get-profile`, {
method: 'GET',
headers: {
Authorization: token || ''
}
})
if (response.status !== 200) {
const _props: PageProps = {profile: false}
return { props: _props }
}
const profile = await response.json()
const _props: PageProps = {profile}
return {
props: _props
}
})
export default withAuthUser({
whenUnauthedBeforeInit: AuthAction.SHOW_LOADER,
whenUnauthedAfterInit: AuthAction.REDIRECT_TO_LOGIN,
LoaderComponent: FullPageLoader,
})(Home);
And the compiler throws this error
./src/pages/index.tsx:74:4
Type error: Argument of type 'FunctionComponent<PageProps> & { getInitialProps?(context: NextPageContext): PageProps | Promise<PageProps>; }' is not assignable to parameter of type 'ComponentType<unknown>'.
Type 'FunctionComponent<PageProps> & { getInitialProps?(context: NextPageContext): PageProps | Promise<PageProps>; }' is not assignable to type 'FunctionComponent<unknown>'.
Types of parameters 'props' and 'props' are incompatible.
Type 'unknown' is not assignable to type 'PageProps'.
72 | whenUnauthedAfterInit: AuthAction.REDIRECT_TO_LOGIN,
73 | LoaderComponent: FullPageLoader,
> 74 | })(Home);
| ^
75 |
I don't understand why he wants a ComponentType<unknow> because type is declared. Tried also to declare directly ({profile}:any)but throws a similar error. How I can get this to work with Typescript?
Finally solved with the required utility type ?
type PageProps = {
profile?: boolean | {
username: string,
name: string,
surname: string
}
}
and also the return type of the exported Home function
export default withAuthUser<PageProps>({
whenUnauthedBeforeInit: AuthAction.SHOW_LOADER,
whenUnauthedAfterInit: AuthAction.REDIRECT_TO_LOGIN,
LoaderComponent: FullPageLoader,
})(Home);

Types error with AxiosResponse and UseQueryResult

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 :)

Type '{ userId: string; }' has no properties in common with type 'AxiosRequestConfig'. | Axios - Next.js with typescript

( Hi comunnity ) I have this piece of code, everything was working fine, but got an error once i create the API.delete function, don't know what is going on there actually
import axios, { AxiosRequestConfig } from "axios";
const API = axios.create({ baseURL: "http://localhost:5000/api" });
// Set header for each request to give permission
API.interceptors.request.use((req: AxiosRequestConfig) => {
if (localStorage.getItem("Auth")) {
req.headers.Authorization = `Bearer ${
JSON.parse(localStorage.getItem("Auth")).token
}`;
}
return req;
});
// login - register - update perfil
export const login = (loginData: {
email: string | null;
password: string | null;
}) => API.post(`/user/login`, loginData);
export const register = (registerData: {
email: string;
password: string;
name: string;
}) => API.post("/user/register", registerData);
export const updatePerfilPhotos = (
photosBase64: { perfil?: string; banner?: string },
id: string
) => API.patch(`/user/update/${id}`, photosBase64);
export const AddNotification = (
userInformation: { userId: string },
id: string
) => API.patch(`/user/notification/${id}`, userInformation);
export const DeleteNotificationOrFriend = (
userInformation: { userId: string },
id: string
) => API.delete(`/user/deleteNotification/${id}`, userInformation);
//
In the API.delete function there's a problem :
(parameter) userInformation: {
userId: string;
}
Type '{ userId: string; }' has no properties in common with type 'AxiosRequestConfig'
What does that mean ? why is that happening, how can i fix this ?
Thanks for your time friends !
I think the delete method signature should be like this,
API.delete(`/user/deleteNotification/${id}`, { data: userInformation })
Refer: https://github.com/axios/axios/issues/897#issuecomment-343715381

Resources