Next.js Discord

Discord Forum

need help with rendering page static with dynamic URL param

Answered
Kümmel posted this in #help-forum
Open in Discord
i'm trying to make my dynamic url page to render static for SEO optimization but i keep getting type errors which i dont understand: Type error: Type 'OmitWithTag<PageProps, keyof PageProps, "default">' does not satisfy the constraint '{ [x: string]: never;
}'.
Property 'id' is incompatible with index signature.
Type 'string' is not assignable to type 'never'.


thats the code:
Answered by Kümmel
in nextjs 15 params are asynchronous and must be awaited. Previously, these were synchronous objects. so i had to change Page props to
type PageProps = {
  params: Promise<{ id: string }>;
}; 
and now i need to await the params and destructure it before using it in the getProduct() function:
// Product page component
export default async function ProductIDPage({ params }: PageProps) {
  const { id } = await params;
  const product = await getProduct(id); 
View full answer

38 Replies

@Jboncz
Can you paste the code in here using tripple back ticks on the front and back?
so it looks like this
back tick is -> ` 🙂
type PageProps = {
  id: string;
};

//get Product from Prisma DB and cache
const getProduct = cache(async (id: string) => {
  const product = await db.product.findUnique({
    where: { id },
  });
  if (!product) return notFound();
  return product;
});

// get all active products and cache
const getAllProductsIDs = cache(async () => {
  const products = await db.product.findMany({
    where: { isAvailableForPurchase: true },
    select: { id: true },
  });
  if (!products) return notFound();
  return products;
});

// get all active product ids for faster loading
export async function generateStaticParams() {
  const products = await getAllProductsIDs();

  // Produkt-IDs as Array
  return products.map((product) => ({
    id: product.id,
  }));
}


export async function generateMetadata({
  id,
}: PageProps): Promise<Metadata> {
  // get product from DB
  const product = await getProduct(id);

  return {
    title: product.name,
    description: product.description,
  };
}

// Define Product-ID PAge
export default async function ProductIDPage({ id }: PageProps) {
  //get product from DB
  const product = await getProduct(id);

  // Hole die Zubehörteile und Features
  const productWithAccessoriesAndFeatures =
    await getProductWithAccessoriesAndFeatures(id);
  if (!productWithAccessoriesAndFeatures) return notFound();

  return (... 
and one last thing, can you pass the full error message like you did above?
well there are a couple which say pretty much the same thing :
.next/types/app/(customerFacing)/products/[id]/page.ts:34:13
Type error: Type 'OmitWithTag<PageProps, keyof PageProps, "default">' does not satisfy the constraint '{ [x: string]: never; 
}'.
  Property 'id' is incompatible with index signature.
    Type 'string' is not assignable to type 'never'.

  32 |
  33 | // Check the prop type of the entry function
> 34 | checkFields<Diff<PageProps, FirstArg<TEntry['default']>, 'default'>>()
     |             ^ 
Thats good ty. Gimme a few mins
to make it clear i have those problems when i run npm run build
Np.
Wait one sec lol deleted a message with some code 😂
type PageParams = {
  params: {
    id: string;
  };
};

// get Product from Prisma DB and cache
const getProduct = cache(async (id: string) => {
  const product = await db.product.findUnique({
    where: { id },
  });
  if (!product) return notFound();
  return product;
});

// get all active products and cache
const getAllProductsIDs = cache(async () => {
  const products = await db.product.findMany({
    where: { isAvailableForPurchase: true },
    select: { id: true },
  });
  if (!products) return notFound();
  return products;
});

// get all active product ids for faster loading
export async function generateStaticParams() {
  const products = await getAllProductsIDs();
  
  // Return params object in the correct structure for Next.js
  return products.map((product) => ({
    params: { id: product.id },
  }));
}

// Define metadata generation function
export async function generateMetadata({ params }: PageParams): Promise<Metadata> {
  // get product from DB
  const product = await getProduct(params.id);
  
  return {
    title: product.name,
    description: product.description,
  };
}


yeah try this.
Make sure to make a seperate page for trying, it would take alot of work to create a reproduction to test for me lol
well only one type error:
Linting and checking validity of types  .Failed to compile.

.next/types/app/(customerFacing)/products/[id]/page.ts:34:29
Type error: Type 'PageParams' does not satisfy the constraint 'PageProps'.
  Types of property 'params' are incompatible.
    Type '{ id: string; }' is missing the following properties from type 'Promise<any>': then, catch, finally, [Symbol.toStringTag]

  32 |
  33 | // Check the prop type of the entry function
> 34 | checkFields<Diff<PageProps, FirstArg<TEntry['default']>, 'default'>>()
     |                             ^
  35 |
  36 | // Check the arguments and return type of the generateMetadata function
  37 | if ('generateMetadata' in entry) { 
well i dont get it i dont use any PageProps and it says 'PageParams' does not satisfy the constraint 'PageProps'.
Its nextjs checking things on compile. Can you send the full .js file in here? Just make sure theres no keys or any other information you dont want public.
The full page with everything before the changes I suggested.
type PageProps = {
  id: string;
};

//get Product from Prisma DB and cache
const getProduct = cache(async (id: string) => {
  const product = await db.product.findUnique({
    where: { id },
  });
  if (!product) return notFound();
  return product;
});

// get all active products and cache
const getAllProductsIDs = cache(async () => {
  const products = await db.product.findMany({
    where: { isAvailableForPurchase: true },
    select: { id: true },
  });
  if (!products) return notFound();
  return products;
});

// get all active product ids for faster loading
export async function generateStaticParams() {
  const products = await getAllProductsIDs();

  // Produkt-IDs as Array
  return products.map((product) => ({
    id: product.id,
  }));
}


export async function generateMetadata({
  id,
}: PageProps): Promise<Metadata> {
  // get product from DB
  const product = await getProduct(id);

  return {
    title: product.name,
    description: product.description,
  };
}

// Define Product-ID PAge
export default async function ProductIDPage({ id }: PageProps) {
  //get product from DB
  const product = await getProduct(id);

  // Hole die Zubehörteile und Features
  const productWithAccessoriesAndFeatures =
    await getProductWithAccessoriesAndFeatures(id);
  if (!productWithAccessoriesAndFeatures) return notFound();

  return (
    <div className="w-full pt-[10vh]">
    </div>
  );
}
  
i had to shorten it as it was too long for dc
Np. As long as the functions are still there we good
ty
sec
but the important parts should be in there
import type { Metadata } from "next"
import { cache } from "react"
import { notFound } from "next/navigation"
import { db } from "@/lib/db" // Assuming you have this import

// Define the params type correctly for App Router
type ProductPageParams = {
  params: {
    id: string
  }
}

// Cache the product fetching function
const getProduct = cache(async (id: string) => {
  const product = await db.product.findUnique({
    where: { id },
  })
  if (!product) return notFound()
  return product
})

// Get all active product IDs and cache the result
const getAllProductsIDs = cache(async () => {
  const products = await db.product.findMany({
    where: { isAvailableForPurchase: true },
    select: { id: true },
  })
  if (!products) return notFound()
  return products
})

// Function to get product with accessories and features
const getProductWithAccessoriesAndFeatures = async (id: string) => {
  // Implement your logic here to fetch product with accessories and features
  const product = await db.product.findUnique({
    where: { id },
    include: {
      accessories: true,
      features: true,
    },
  })
  return product
}

// Generate static paths for all active products
export async function generateStaticParams() {
  const products = await getAllProductsIDs()

  return products.map((product) => ({
    id: product.id,
  }))
}

// Generate metadata for the product page
export async function generateMetadata({ params }: ProductPageParams): Promise<Metadata> {
  // Get product from DB using the ID from params
  const product = await getProduct(params.id)

  return {
    title: product.name,
    description: product.description,
  }
}

// Product page component
export default async function ProductIDPage({ params }: ProductPageParams) {
  // Get product from DB using the ID from params
  const product = await getProduct(params.id)

  // Get the accessories and features
  const productWithAccessoriesAndFeatures = await getProductWithAccessoriesAndFeatures(params.id)
  if (!productWithAccessoriesAndFeatures) return notFound()

  return (
    <div className="w-full pt-[10vh]">
      {/* Your product page content here */}
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      {/* Add more product details as needed */}
    </div>
  )
}


Okay try this.
Tell me if you get that same error
The 'biggest' thing was how your defining the PageProps

nextjs expects

type ProductPageParams = {
  params: {
    id: string
  }
}


I know that for sure.
same shit
Linting and checking validity of types  ...Failed to compile.

.next/types/app/(customerFacing)/products/[id]/page.ts:34:29
Type error: Type 'ProductPageParams' does not satisfy the constraint 'PageProps'.
  Types of property 'params' are incompatible.
    Type '{ id: string; }' is missing the following properties from type 'Promise<any>': then, catch, finally, [Symbol.toStringTag]

  32 |
  33 | // Check the prop type of the entry function
> 34 | checkFields<Diff<PageProps, FirstArg<TEntry['default']>, 'default'>>()
     |                             ^
  35 |
  36 | // Check the arguments and return type of the generateMetadata function
  37 | if ('generateMetadata' in entry) { 
but i dont wanna waste your time bro haha
All good man. One last thing, try replacing PageProps with

type PageProps = {
  params: {
    id: string
  }
  searchParams: Record<string, string | string[] | undefined>
}
idk if thatll work, but It might.
you mean "ProductPageParams" ?
Oh oh. Im an idiot this is what happens when I dont have actual environment lol why did I change the name to ProductPageParams
import type { Metadata } from "next"
import { cache } from "react"
import { notFound } from "next/navigation"
import { db } from "@/lib/db"

// Define the params type correctly for App Router
type PageProps = {
  params: {
    id: string
  }
  searchParams: Record<string, string | string[] | undefined>
}

// Cache the product fetching function
const getProduct = cache(async (id: string) => {
  const product = await db.product.findUnique({
    where: { id },
  })
  if (!product) return notFound()
  return product
})

// Get all active product IDs and cache the result
const getAllProductsIDs = cache(async () => {
  const products = await db.product.findMany({
    where: { isAvailableForPurchase: true },
    select: { id: true },
  })
  if (!products) return notFound()
  return products
})

// Function to get product with accessories and features
const getProductWithAccessoriesAndFeatures = async (id: string) => {
  // Implement your logic here to fetch product with accessories and features
  const product = await db.product.findUnique({
    where: { id },
    include: {
      accessories: true,
      features: true,
    },
  })
  return product
}

// Generate static paths for all active products
export async function generateStaticParams() {
  const products = await getAllProductsIDs()

  return products.map((product) => ({
    id: product.id,
  }))
}

// Generate metadata for the product page
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
  // Get product from DB using the ID from params
  const product = await getProduct(params.id)

  return {
    title: product.name,
    description: product.description,
  }
}

// Product page component
export default async function ProductIDPage({ params, searchParams }: PageProps) {
  // Get product from DB using the ID from params
  const product = await getProduct(params.id)

  // Get the accessories and features
  const productWithAccessoriesAndFeatures = await getProductWithAccessoriesAndFeatures(params.id)
  if (!productWithAccessoriesAndFeatures) return notFound()

  return (
    <div className="w-full pt-[10vh]">
      {/* Your product page content here */}
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      {/* Add more product details as needed */}
    </div>
  )
}
np still exactly same error. anywas thank you very very much i have to go off now, i have to get up early tomorrow morning
Alrighty. np.
@Jboncz Alrighty. np.
broo i got it :thinkaboutit:
in nextjs 15 params are asynchronous and must be awaited. Previously, these were synchronous objects. so i had to change Page props to
type PageProps = {
  params: Promise<{ id: string }>;
}; 
and now i need to await the params and destructure it before using it in the getProduct() function:
// Product page component
export default async function ProductIDPage({ params }: PageProps) {
  const { id } = await params;
  const product = await getProduct(id); 
Answer