niels van hoof
niels van hoof

Reputation: 489

Next js failing on build with getStaticProps due to param being undefined

weird error started appearing that's causing builds to fail,

we have a post/[id].tsx file inside of our pages dir, this file uses getStaticProps and getStaticPaths

-- props

export const getStaticProps: GetStaticProps = async ({ params }) => {
  const res: Response = await fetch(`${baseUrl}/api/products/${params.id}`);

  const data: Product[] = await res.json();

  return {
    props: {
      data,
    },
  };
};

-- paths

export const getStaticPaths: GetStaticPaths = async () => {
  const res: Response = await fetch(`${baseUrl}/api/products`);
  const { data } = await res.json();

  const paths = data.map((product: Product) => ({
    params: { id: product.id.toString() },
  }));
  return { paths, fallback: "blocking" };
};

running npm run dev locally and everything works as expected, but running npm run build and the error

Type error: Object is possibly 'undefined'.

inside of the getStaticProps function

> 12 |   const res: Response = await fetch(`${baseUrl}/api/products/${params.id}`);
                                                                      ^

Now the weird thing is that the currently deployed build on vercel is using the exact same code to build this page and nothing has changed from it. But now builds are suddenly failing?

Upvotes: 5

Views: 4135

Answers (2)

Chukwuamaka Osuji
Chukwuamaka Osuji

Reputation: 71

This is an offshoot of @Pranta's answer above, with some modifications. While Pranta's solution solves the problem to a great extent, Typescript will issue the same warning within the id variable declaration, although this might not cause the build to fail. Before moving on, it's important to note that the warning shows up because Next's type definition for the params object is ParsedUrlQuery | undefined.

One way to resolve the issue and completely eliminate the warning is by asserting the type of the params object to ParsedUrlQuery, like this:

// The import should happen automatically in VSCode, but if it doesn't
import { ParsedUrlQuery } from 'querystring';

const id = (params as ParsedUrlQuery).id;
const res: Response = await fetch(`${baseUrl}/api/products/${id}`);

While this works, it is still not the best solution. A better solution, which I recommend, is checking that the params object is actually defined before making the API call in the getStaticProps function. This way, you can also avoid running into issues subsequently. Hence, we have:

if (params) {
  const id = params.id;
  const res: Response = await fetch(`${baseUrl}/api/products/${id}`);
}

We can refactor the code and add an extra check to ensure that a value for the id path parameter was actually retrieved from the getStaticPaths function.

if (params && params.id) {
  const res: Response = await fetch(`${baseUrl}/api/products/${params.id}`);
}

Lastly, because the getStaticProps function expects a value to be returned, we have to specify a default return value that mimics the structure of the return value expected by the function, as seen below.

export const getStaticProps: GetStaticProps = async ({ params }) => {
  if (params && params.id) {
    const res: Response = await fetch(`${baseUrl}/api/products/${params.id}`);
    const data: Product[] = await res.json();
    return {
      props: { data },
    };
  }

  // Here, I'm returning an error property in the props object, but you can choose to return something else that suits your need.
  return {
    props: { error: true },
  };
};

Upvotes: 7

Pranta
Pranta

Reputation: 3695

The problem here is that next.js is doing a type-check here and typescript thinks your params might be undefined here. Just tell typescript it's not.

  const id = params.id!
  const res: Response = await fetch(`${baseUrl}/api/products/${id}`);

This should work.

Upvotes: 2

Related Questions