Next.js Discord

Discord Forum

I can't build in Next Js 15.0.2 due to params in a page (dynamic segment)

Answered
West African Crocodile posted this in #help-forum
Open in Discord
Avatar
West African CrocodileOP
Hi there,

I searched other threads before creating. Found similar questions. But the approved solutions are not working for me. So I'm creating mine.

This code works while I do pnpm run dev, I can see the post loaded.

// app/blog/[slug]/page.tsx
import { notFound } from "next/navigation";
import BlogPost from "@/components/BlogPost";
import db from "@/db/index";
import { Post } from "@/db/schema";
import { eq } from "drizzle-orm";

type Props = {
  params: Promise<{ slug: string }>;
};

export default async function Page(props: Props) {
  const { slug } = await props.params;

  const post = await db.select().from(Post).where(eq(Post.slug, slug)).limit(1);

  if (!post.length) {
    notFound();
  }

  return <BlogPost post={post[0]} />;
}


But If I do pnpm run build then I get this error:

   Linting and checking validity of types  .Failed to compile.

.next/types/app/blog/page/[page]/page.ts:34:29
Type error: Type '{ params: { page: string; }; }' does not satisfy the constraint 'PageProps'.
  Types of property 'params' are incompatible.
    Type '{ page: 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) {
 ELIFECYCLE  Command failed with exit code 1.


I also tried with things like params: Promise<{slug: string}> | {slug:string}

And matched how it was done here:
https://nextjs.org/docs/canary/app/building-your-application/upgrading/version-15#asynchronous-page
https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes
https://nextjs-forum.com/post/1299939488654561361

I'm being unable to solve the problem.
What I'm doing wrong ?
Answered by joulev
params: Promise<{ page: string }> instead of { page: string }
View full answer

39 Replies

Avatar
That is a error in types I believe
Can you send type of BlogPost?
Avatar
West African CrocodileOP
Hi @Anay-208 !
I'm using drizzle orm (or trying 😅 )

So the types for the BlogPost are the inferred types from the Schema.

import { SelectPost } from "@/db/schema";

interface BlogPostProps {
  post: SelectPost;
}

export default function BlogPost({ post }: BlogPostProps) {


I'm "glob importing" it from src\db\schema\index.ts with export * from "./post";

And this is the schema:

import { InferSelectModel, InferInsertModel, sql } from "drizzle-orm";
import { pgTable as table } from "drizzle-orm/pg-core";
import * as t from "drizzle-orm/pg-core";

const timestamps = {
  updatedAt: t.timestamp({ withTimezone: true, mode: "string" }),
  createdAt: t
    .timestamp({ withTimezone: true, mode: "string" })
    .defaultNow()
    .notNull(),
  deletedAt: t.timestamp({ withTimezone: true, mode: "string" }),
};

export const Post = table(
  "Post",
  {
    id: t.integer().primaryKey().generatedAlwaysAsIdentity(),
    title: t.text().notNull(),
    slug: t.text().notNull().unique(),
    excerpt: t.text().notNull(),
    author: t.text().notNull(),
    category: t.text().notNull(),
    tags: t
      .text()
      .array()
      .notNull()
      .default(sql`ARRAY[]::text[]`),
    readingTime: t.integer().notNull(),
    content: t.text().notNull(),
    components: t
      .text()
      .array()
      .notNull()
      .default(sql`ARRAY[]::text[]`),
    ...timestamps,
  },
  (table) => {
    return {
      slugIndex: t.uniqueIndex("slug_idx").on(table.slug),
      titleIndex: t.index("title_idx").on(table.title),
    };
  }
);

export type SelectPost = InferSelectModel<typeof Post>;
export type InsertPost = InferInsertModel<typeof Post>;


I thought my schema types should have something to do with the error... but v0.dev told me it was a problem with it being awaited and so... So I got pretty confused with these new async changes I think.
Avatar
if build is running on prod, have you added env variables?
Avatar
West African CrocodileOP
I've used this to connect.
My .env just have DATABASE_URL=....the connection string....
I was just trying to build on localhost
import "dotenv/config";
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";

import * as schema from "@/db/schema";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL!,
});

const db = drizzle(pool, {
  schema,
  logger: true,
});

// export type db = typeof db;

export default db;
Avatar
are you running build locally?
Avatar
West African CrocodileOP
pnpm run build

yep 😀
Avatar
I'm unsure about drizzle can you try using as when setting types, and see if you still get the error
and also console log the item
Avatar
West African CrocodileOP
Uhmm... I only saw the usage of as here:
https://nextjs.org/docs/canary/app/building-your-application/upgrading/version-15#asynchronous-page

Like: const cookieStore = cookies() as unknown as UnsafeUnwrappedCookies

There's also something similar for draftMode and headers but not for page, at least there.

Is this what you mean ? There should be an UnsafeUnwrappedPage too ? I'm not really sure what should use for as in my case.
Oh... I'm seeing next/server has this:
export type { UnsafeUnwrappedParams } from 'next/dist/server/request/params'
Avatar
No, in db operation
When you read from db
Avatar
West African CrocodileOP
This ?
const post = await db.select().from(Post).where(eq(Post.slug, slug)).limit(1);
Avatar
Yup, try to set as type. Also console log the post
Avatar
West African CrocodileOP
I tried to use as Post and as SelectPost but doesn't seem to like it 😅
Image
Image
Light theme sorry 😅
In theory, with drizzle, I'm already passing the type, in the .from(Post) It's all what it needs to make the select.
In fact, I can load the page with the data when running with pnpm run dev
mid english, mid spanish 😅
Image
Avatar
The bug is in app/blog/page/[page]/page.tsx, not app/blog/[slug]/page.tsx
Avatar
West African CrocodileOP
oh maybe not the type, just the schema.... but meh it work on dev.
Avatar
The bug is not relevant to drizzle or blog content or anything
Paste the prop type of app/blog/page/[page]/pags.tsx here
Avatar
West African CrocodileOP
ohhhh
the route is other : /
It's true I have some different routes, where I'm trying different things.
Ah yes, this is where I tried to implement a pagination.

import { PaginationComponent } from "@/components/Pagination";
import { getBlogPosts } from "@/lib/blog";

export default async function BlogPage({
  params,
}: {
  params: { page: string };
}) {
  const { page } = await params;
  const currentPage = parseInt(page, 10) || 1;
  const { posts, totalPages } = await getBlogPosts(currentPage, 2);

  return (
    <div>
      {/* Render your blog posts here */}
      <ul className="flex flex-col gap-4">
        {posts.map((post, index) => (
          <li key={index}>
            <h2>{post.title}</h2>
            <p>{post.excerpt}</p>
            <p>Published on: {new Date(post.createdAt).toLocaleDateString()}</p>
            {post.updatedAt && (
              <p>Updated on: {new Date(post.updatedAt).toLocaleDateString()}</p>
            )}
            <p>Category: {post.category}</p>
            <p>Author: {post.author}</p>
            <p>Reading time: {post.readingTime}</p>
            <p>Tags: {post.tags.join(", ")}</p>
          </li>
        ))}
      </ul>

      <PaginationComponent
        currentPage={currentPage}
        totalPages={totalPages}
        maxPageNumbers={3}
      />
    </div>
  );
}
Avatar
params: Promise<{ page: string }> instead of { page: string }
Answer
Avatar
West African CrocodileOP
Image
I'm trying to build after changing it
haha my app feels like a mine field atm....
   Linting and checking validity of types  ..Failed to compile.

.next/types/app/post/page.ts:2:24
Type error: File 'C:/dev/nextjs/next-stable-pnpm/src/app/post/page.tsx' is not a module.

  1 | // File: C:\dev\nextjs\next-stable-pnpm\src\app\post\page.tsx
> 2 | import * as entry from '../../../../src/app/post/page.js'
    |                        ^
  3 | import type { ResolvingMetadata, ResolvingViewport } from 'next/dist/lib/metadata/types/metadata-interface.js'
  4 |
  5 | type TEntry = typeof import('../../../../src/app/post/page.js')
 ELIFECYCLECommand failed with exit code 1.
another file....
so my initial problem is solved I guess
I need 5 min, then I could check further (bit busy)
Avatar
Different bug, different post. Open a new post if you need help. Though the bug is in app/post/page.tsx, go there and try to see if something is wrong first
Avatar
West African CrocodileOP
Sure, many thanks for helping me 🙂 both of you !