UNPKG

@alessiofrittoli/next-api

Version:
168 lines (165 loc) 4.72 kB
import { ResolvingMetadata, Metadata } from 'next'; /** * Namespace containing types related to Next.js Pages. * */ declare namespace Page { /** * Represent `Awaited<Page.Props[ 'params' ]>`. * */ type Params = Record<string, string | string[]>; /** * Represent a URLSearchParam value. * */ type SearchParam = string | string[] | null; /** * Next.js Page URL Search Params. * * @template T Custom type joined with the default type for `props.searchParams`. */ type SearchParams<T extends Record<string, Page.SearchParam> = Record<string, Page.SearchParam>> = T & { [x: string]: Page.SearchParam; }; /** * Default Next.js Page Component props. * * @template T Custom type assigned to `props.params`. * @template U Custom type joined with the default type for `props.searchParams`. * * @example * * #### Basic usage * * ```tsx * // src/app/dynamic/[slug]/page.tsx * const DynamicPage: React.FC<Page.Props> = ( * async props => { * * const params = await props.params * const { slug } = params // `slug` is now type of `string | string[] | undefined` * * return ( * <h1>Dynamic page - { slug }</h1> * ) * * } * ) * ``` * * --- * * @example * * #### `Page.Props[ 'params' ]` safe access * * ```tsx * // src/app/dynamic/[slug]/page.tsx * const DynamicPage: React.FC<Page.Props<{ slug: string }>> = ( * async props => { * * const params = await props.params * const { slug } = params // safe access to `params.slug` * * return ( * <h1>Dynamic page - { slug }</h1> * ) * * } * ) * ``` * * --- * * @example * * #### Catch-all Page * * ```tsx * // src/app/catch-all/[...rest]/page.tsx * const CatchAllPage: React.FC<Page.Props<{ rest: string[] }>> = ( * async props => { * * const params = await props.params * const { rest } = params // safe access to `params.rest` * * return ( * <h1>Catch-all page - { rest.join( ' - ' ) }</h1> * ) * * } * ) * ``` * * --- * * @example * * #### Page with search params * * ```tsx * // src/app/page.tsx * const PageWithSearchParams: React.FC<Page.Props> = ( * async props => { * * const searchParams = await props.searchParams * const { param } = searchParams || {} // `param` is now type of `string | string[] | null | undefined` * * return ( * <h1>Page with search param - { param }</h1> * ) * * } * ) * ``` * * --- * * @example * * #### Page with typed search params * * ```tsx * // src/app/page.tsx * const PageWithSearchParams: React.FC<Page.Props<never, { param: Page.SearchParam }>> = ( * async props => { * * const searchParams = await props.searchParams * const { param } = searchParams || {} // safe access to `searchParams?.param` - `param` is now type of `string | string[] | null | undefined` * * return ( * <h1>Page with search param - { param }</h1> * ) * * } * ) * ``` */ type Props<T extends Page.Params = Page.Params, U extends Record<string, Page.SearchParam> = Record<string, Page.SearchParam>> = { /** Page parameters. */ params: Promise<T>; /** Page URL Search Params. */ searchParams?: Promise<Page.SearchParams<U>>; }; /** * The Next.js React.FC Page `props` with awaited `params`. * * @template T Custom type assigned to `props.params`. * @template U Custom type joined with the default type for `props.searchParams`. * @template V Indicates whether `props.searchParams` are awaited or not. Default: `false`. */ interface AwaitedProps<T extends Page.Params = Page.Params, U extends Record<string, Page.SearchParam> = Record<string, Page.SearchParam>, V extends boolean = false> { /** Page parameters. */ params: T; /** Page URL Search Params. */ searchParams?: V extends false ? Promise<Page.SearchParams<U>> : Page.SearchParams<U>; } /** * The Next.js Page generateMetadata handler with awaited `params`. * * @template T Custom type assigned to `props`. */ type GenerateMetadata<T = unknown> = (props: T, parent: Awaited<ResolvingMetadata>) => Metadata | Promise<Metadata>; } export { Page as P };