What is the Typescript type of a next page function using the app router? #62558
-
When using the pages router, the typescript type of a page function is import { GetServerSideProps, NextPage } from 'next'
const MyPage: NextPage<MyPageProps> = ({ user }) => {
return <span>{user.name}</span>
})
export const getServerSideProps: GetServerSideProps = async ({ query }) => {
const { id } = query
const user = await db.getUser({ id })
return {
props: {
user,
}
}
}
export type MyPageProps = {
user: User
}
export default MyPage What is the equivalent to these types when using the app router? I'm trying to get to something like this: const MyPage = async ({ params: { id }) => {
const user = await db.getUser({ id })
return <span>{user.name}</span>
}) What type do I use, so that |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments
-
I think it is import { NextPage } from 'next'; Where But you still have to specify the type for your params, for example: type ExamplePageProps = {
params: {
locale: 'en' | 'es';
};
};
const ExamplePage: NextPage<ExamplePageProps> = async ({params}) => {
const data = await sdk.getContentByLocale(params.locale) // just an example of usage
return (
<PageLayout>
<PageContent data={data} />
</PageLayout>
);
} |
Beta Was this translation helpful? Give feedback.
-
Hi, As far as I remember, the library doesn't have a type signature for the page props, but it is pretty simple: export default function Page({
params,
searchParams,
}: {
params: { slug: string }
searchParams: { [key: string]: string | string[] | undefined }
}) {
return <h1>My Page</h1>
} I think part of the reason is that, the I also think that maybe they could try to give some fix with the Next.js Plugin, https://nextjs.org/docs/app/building-your-application/configuring/typescript#plugin-features, which will have more features coming soon. What the NextPage type on the other response does is, it simply annotate the props, and type the return, as well as make it optional to include a getInitialProps method on the page, which is a huge no go for me, since that API is not supported in App Router.
|
Beta Was this translation helpful? Give feedback.
-
Here's some TS I wrote that satisfies that need: declare global {
type Prettify<T> = {
[K in keyof T]: T[K];
} & {};
type UnionToIntersection<T> = Prettify<
(T extends any ? (x: T) => any : never) extends (x: infer R) => any
? R
: never
>;
interface PageProps<
TParams extends string = never,
TSearchParams extends string = never
> {
params: UnionToIntersection<
{
[K in TParams]: {
[F in K extends `...${infer U}` ? U : K]: K extends `...${string}`
? string[]
: string;
};
}[TParams]
>;
searchParams: { [K in TSearchParams]?: string | string[] };
}
} Use it like: export default async function MyPage(props: PageProps<"id" | "...slug", "index">) {
console.log(props.params); // { id: "foo", slug: ["one", "two"] }
console.log(props.searchParams); // { index?: string | string[] | undefined }
return <div>stuff</div>
} |
Beta Was this translation helpful? Give feedback.
-
Here is an alternative to the above: type Empty = {
[key: PropertyKey]: never;
};
type PathParameters<ParametersType extends string = never> = [ParametersType] extends [never]
? Empty
: {
[ParameterType in ParametersType as ParameterType extends `...${infer CatchAllParameterType}` ? CatchAllParameterType : never]: string[];
} & {
[ParameterType in ParametersType as ParameterType extends `[...${infer OptionalCatchAllParameterType}]` ? OptionalCatchAllParameterType : never]?: string[];
} & {
[ParameterType in ParametersType as ParameterType extends `...${string}` | `[...${string}]` ? never : ParameterType]: string;
};
type QueryParameters<ParametersType extends string = never> = [ParametersType] extends [never]
? Empty
: {
[ParameterType in ParametersType]?: string | string[];
};
type PageProps<PathParametersType extends string = never, QueryParametersType extends string = never> = {
params: PathParameters<PathParametersType>;
searchParams: QueryParameters<QueryParametersType>;
}; or a bit less verbose: type PageProps<P extends string = never, Q extends string = never> = {
params: [P] extends [never]
? { [k: PropertyKey]: never }
: {
[K in P as K extends `...${infer I}` ? I : never]: string[];
} & {
[K in P as K extends `[...${infer I}]` ? I : never]?: string[];
} & {
[K in P as K extends `...${string}` | `[...${string}]` ? never : K]: string;
};
searchParams: [Q] extends [never]
? { [k: PropertyKey]: never }
: { [K in Q]?: string | string[] };
}; Usage is the same but it also handles optional catch-all path parameters: export default async function MyPage(props: PageProps<"foo" | "...bar" | "[...baz]", "a" | "b">) {
console.log(props.params); // { foo: string, bar: string[], baz?: string[] | undefined }
console.log(props.searchParams); // { a?: string | string[] | undefined, b?: string | string[] | undefined }
return <div>stuff</div>
} |
Beta Was this translation helpful? Give feedback.
-
Short answer // app/blog/[slug]/page.tsx
type PageProps = {
params: { slug: string }
searchParams?: { [key: string]: string | string[] | undefined }
}
export default async function Page({ params, searchParams }: PageProps): Promise<JSX.Element> {
// fetch data ...
return <article>{params.slug}</article>
} Common patterns
Notes
Docs |
Beta Was this translation helpful? Give feedback.
-
Hi, we finally have an alternative! https://nextjs.org/docs/app/api-reference/config/typescript#route-aware-type-helpers |
Beta Was this translation helpful? Give feedback.
Hi, we finally have an alternative! https://nextjs.org/docs/app/api-reference/config/typescript#route-aware-type-helpers