Ciprian
Ciprian

Reputation: 289

Type Error in Next.js Route: "Type '{ params: { id: string; }; }' does not satisfy the constraint 'PageProps'" (NextJS 15)

I'm encountering an issue when trying to use asynchronous parameters in a Next.js 15 app. I want to extract the slug parameter from params, which is returned as a Promise.

Here's my current setup in page.tsx:

type tParams = Promise<{ slug: string[] }>;

export default async function Challenge({ params }: { params: tParams }) {
  const { slug } = await params;
  const productID = slug[1];

  // other code here
}

When I run npm run build, I get this error:

Type error: Type '{ params: { id: string; }; }' does not satisfy the constraint 'PageProps'. Types of property 'params' are incompatible. Type '{ id: string; }' is missing the following properties from type 'Promise': then, catch, finally, [Symbol.toStringTag]

It seems like the type for params is causing issues, possibly because Next.js expects a different structure for params.

What I’ve Tried

Question

How can I correctly type the params object for asynchronous access in Next.js 15, or is there a different recommended approach for this?

Upvotes: 23

Views: 16512

Answers (15)

Mayur Chavan
Mayur Chavan

Reputation: 1051

Failing code -->

export default function Page({
  params,
}: {
  params: { slug: string };
}) {
  const pageData = vslConfig.pages[params.slug as keyof typeof vslConfig.pages];

Working Code --

interface PageProps {
  params: Promise<{ slug: string }>;
}

export default async function Page(props: PageProps) {
  const { slug } = await props.params;
  const pageData = vslConfig.pages[slug as keyof typeof vslConfig.pages];

Upvotes: 0

TechGolemn
TechGolemn

Reputation: 558

From the example in the migration guide they show that you can't use the destructured members of an asynchronous page props...

Maybe try this change -

type tParams = Promise<{ slug: string[] }>;

export default async function Challenge(props: { params: tParams }) {
  const { slug } = await props.params;
  const productID = slug[1];

  // other code here
}

Upvotes: 15

DoudGaya
DoudGaya

Reputation: 69

In nextJS 15 params is a promise and you have to await it,you also have to be specific destructuring your params You can solve this issues in two ways, using async await. or by importing use from 'react' on a client component.

Using Async Await

type tParams = Promise<{ slug: string[] }>;

export default async function Challenge({ params }: { params:  tParams }) {
  const { slug }: {slug: string[]} = await params; // fix this line
  const productID = slug[1];

  // other code here
}

using import from react

 import use from 'react' // import this line

type tParams = Promise<{ slug: string[] }>;

export default function Challenge({ params }: { params:  tParams }) {
  const { slug }: {slug: string[]} = use(params) ; // fix this line
  const productID = slug[1];

  // other code here
}

Upvotes: 1

frankiefab
frankiefab

Reputation: 1

Here’s how I fix this issue:

Previously it looked like this:

export default async function Page({
  params,
}: {
  params: { slug: string };
}) {
  const slug = params.slug;
  const response = await getProjectBySlug(slug);

Then, I changed it to:

export default async function Page(props: {
  params: Promise<{ slug: string }>;
}) {
  const params = await props.params;
  const response = await getProjectBySlug(params.slug);

Upvotes: 0

Kanan Farzali
Kanan Farzali

Reputation: 1053

install npx @next/codemod@canary next-async-request-api . and then const BlogPage = async ({ params }: { params: Promise<{ id: string }> }) => { const { id } = await params; const blog = blogs.find((blog) => blog.id === id); return JSX };

Upvotes: 0

Mohsin Hassan
Mohsin Hassan

Reputation: 1

Here is how fix this issue:

import Link from "next/link";
import photos, { Photo } from "@/lib/";
import PhotoCard from "@/components/photo-card";
export const generateStaticParams = () => {
  return photos.map(({ id }) => ({
    id: String(id),
  }));
};
export type paramsType = Promise<{ id: string }>;

export default async function PhotoPage(props: { params: paramsType }) {
  const { id } = await props.params;
  const photo: Photo | undefined = photos.find((p) => p.id === id);

  if (!photo) {
    return <div>Photo not found</div>;
  }

  return (
    <section className="py-24">
      <div className="container">
        <div>
          <Link
            href="/photos"
            className="font-semibold italic text-sky-600 underline"
          >
            Back to photos
          </Link>
        </div>
        <div className="mt-10 w-1/3">
          <PhotoCard photo={photo} />
        </div>
      </div>
    </section>
  );
}

Upvotes: 0

G.N
G.N

Reputation: 1

You can write it like this.(App Router)

import { EventDetail } from "@/components/organisms/event-detail";

export default async function EventPage({ params }: { params: Promise<{ 
eventId: string }> }) {

    const { eventId } = await params;

    return (
        <main className="">
           <EventDetail eventId={eventId} />
        </main>
    );
}

Upvotes: 0

Amar YASSA
Amar YASSA

Reputation: 129

I fixed the issue by doing this

without async await


import { use } from "react";
    
export default function CategoryDetail({params}: {params: Promise<{ id: string }>}) {
const { id } = use(params);
...

with async await

    
export default async function CategoryDetail({params}: {params: Promise<{ id: string }>}) {
const { id } = await params;
...

Upvotes: 12

yusufie
yusufie

Reputation: 173

There is documentation about Asynchronous Page in the Next.js:

https://nextjs.org/docs/app/building-your-application/upgrading/version-15#asynchronous-page

Try that approach, which is in the Next.js documentation:

export default async function Challenge(
 props: {
  params: Promise<{ slug: string }>;
 }
) {
 const params = await props.params;
 const productID = params.slug[1];
 // const productID = params.slug;
 // other code here
}

Upvotes: 0

Giorgi Gvimradze
Giorgi Gvimradze

Reputation: 2129

For even the projects that run v14 have to be updated using some scenarios mentioned in here. In my case the issue was with async server components receiving params as props. Here is a general solution mentioned in the source documentation:

type Params = Promise<{ slug: string }>
type SearchParams = Promise<{ [key: string]: string | string[] | undefined }>
 
export async function generateMetadata(props: {
  params: Params
  searchParams: SearchParams
}) {
  const params = await props.params
  const searchParams = await props.searchParams
  const slug = params.slug
  const query = searchParams.query
}
 
export default async function Page(props: {
  params: Params
  searchParams: SearchParams
}) {
  const params = await props.params
  const searchParams = await props.searchParams
  const slug = params.slug
  const query = searchParams.query
}

Upvotes: 0

Abdulazeez Onadipe
Abdulazeez Onadipe

Reputation: 1

Do not destructure slug again, I used this format and it worked fine,

const Page = async ({ params }: { params: Promise<{ id: string }> }) => {

const id = (await params).id;

Upvotes: 0

Vanam saiguna
Vanam saiguna

Reputation: 41

install this npx @next/codemod@latest next-async-request-api .

type tParams = Promise<{ slug: string[] }>;

export default async function Challenge({ params }: { params: tParams }) {
  const { slug } = await params;
  const productID = slug[1];
}

just install it you did correct

Upvotes: 3

Dhanush Prabakaran
Dhanush Prabakaran

Reputation: 31

Nextjs 15 dynamic rendering works with this pattern

export default async function PostPage(params: { 
 params: Promise<{ slug: string }>;) {
  const slug = await(params).slug;
  return <Block slug={slug}/>
}

Upvotes: 2

Mustafa Ahmadi
Mustafa Ahmadi

Reputation: 1

based on nextjs15 docs, you can do this:

export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const slug = (await params).slug
  return <div>My Post: {slug}</div>
}

Upvotes: 0

hello_world
hello_world

Reputation: 1

type tParams = { slug: string[] };

export default async function Challenge({ params }: { params: tParams }) {
  // No need to await `params` here since it's not a Promise anymore
  const { slug } = params;
  const productID = slug[1];

  // other code here
}

Upvotes: 0

Related Questions