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

enter image description here

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


Solution 1:[1]

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
}

Solution 2:[2]

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

Solution 3:[3]

You can use like this;

type PageProps = {
  isAuthanticated: boolean,
  categories?: CategoryType[]
}

export const getServerSideProps: GetServerSideProps = async (context) => {
  const _props: PageProps = {
    isAuthanticated: auth,
    categories: data.results
  }
  return { props: _props }
};

const Category: NextPage<PageProps> = (props) => {
  return(
    ...
  )
};

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 David Deutsch
Solution 2
Solution 3 MehmetDemiray