Tipar Page Params no Next.js App Router
Domine a tipagem de page params no Next.js App Router. De rotas dinâmicas simples até searchParams e generateStaticParams, tudo com exemplos prontos pra usar.
Por que isso é importante
Tipar Page Params no Next.js App Router. Domine a tipagem de page params no Next.js App Router. De rotas dinâmicas simples até searchParams e generateStaticParams, tudo com exemplos prontos pra usar.
Como Funcionam os Page Params no App Router
No Next.js App Router, cada page.tsx recebe props automaticamente. As duas mais importantes são params e searchParams. O params traz os segmentos dinâmicos da URL (aquele [slug] ou [id] no nome da pasta). O searchParams traz os query parameters (?page=2&sort=desc).
A pegadinha é que no Next.js 15+, tanto params quanto searchParams são Promises. Isso mudou em relação ao Next.js 13/14. Se você tá migrando, precisa adaptar a tipagem. No Next.js 14, params era um objeto síncrono. Agora você precisa fazer await.
Galera que ignora essa mudança acaba com TypeScript reclamando em todo canto. E pior: se desliga o strict mode pra parar os erros, perde toda a segurança que o TypeScript dá. O caminho certo é tipar direito desde o início.
Passo a Passo: Tipando Params e SearchParams
Vamos montar a tipagem do zero. Cada passo cobre um cenário que você vai encontrar no dia a dia.
Exemplos Práticos de Tipagem de Params
Vamos ver código real. Cada exemplo cobre um caso que aparece em projetos de verdade.
Rota Dinâmica Simples: [slug]
// app/blog/[slug]/page.tsx
// Define o tipo dos params
type Params = {
slug: string;
};
// Next.js 15+: params é Promise
type PageProps = {
params: Promise<Params>;
};
export default async function BlogPost({ params }: PageProps) {
const { slug } = await params;
// slug agora é string tipada
const post = await getPost(slug);
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}
Rotas com Múltiplos Segmentos: [category]/[id]
// app/products/[category]/[id]/page.tsx
type Params = {
category: string;
id: string;
};
type PageProps = {
params: Promise<Params>;
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
};
export default async function ProductPage({ params, searchParams }: PageProps) {
const { category, id } = await params;
const { sort, color } = await searchParams;
const product = await getProduct(category, id);
// sort é string | string[] | undefined
// TypeScript te obriga a tratar cada caso
return <div>{product.name}</div>;
}
Catch-all Routes: [...slug]
// app/docs/[...slug]/page.tsx
// Catch-all: slug é um array de strings
type Params = {
slug: string[];
};
type PageProps = {
params: Promise<Params>;
};
export default async function DocsPage({ params }: PageProps) {
const { slug } = await params;
// slug = ["getting-started", "installation"]
// para URL /docs/getting-started/installation
const path = slug.join("/");
const doc = await getDoc(path);
return <div>{doc.content}</div>;
}
// Optional catch-all: [[...slug]]
// slug pode ser undefined (página raiz)
type OptionalParams = {
slug?: string[];
};
generateStaticParams Tipado
// app/blog/[slug]/page.tsx
type Params = {
slug: string;
};
// generateStaticParams retorna array do tipo Params
export async function generateStaticParams(): Promise<Params[]> {
const posts = await getAllPosts();
return posts.map((post) => ({
slug: post.slug,
}));
}
// Com múltiplos params
// app/products/[category]/[id]/page.tsx
type ProductParams = {
category: string;
id: string;
};
export async function generateStaticParams(): Promise<ProductParams[]> {
const products = await getAllProducts();
return products.map((p) => ({
category: p.category,
id: p.id.toString(), // params são sempre string
}));
}
SearchParams Tipados com Validação
// Tipo específico para seus search params
type SearchParams = {
page?: string;
sort?: "asc" | "desc";
category?: string;
};
type PageProps = {
params: Promise<{ slug: string }>;
searchParams: Promise<SearchParams>;
};
export default async function ListPage({ searchParams }: PageProps) {
const { page = "1", sort = "desc", category } = await searchParams;
// page é string, converta pra number quando precisar
const currentPage = parseInt(page, 10);
// sort já está tipado como "asc" | "desc"
const items = await getItems({
page: currentPage,
sort,
category: category ?? "all",
});
return <ItemList items={items} />;
}
Repare que params sempre são strings. Mesmo que sua URL tenha /products/123, o id chega como "123" e não como number. Isso é do HTTP: tudo na URL é texto. A conversão pra number fica por sua conta, e o TypeScript te lembra disso.
Erros Comuns com Page Params Tipados
Erros que derrubam seu build
Acessar params sem await no Next.js 15+: params agora é Promise. Se você faz const { slug } = params sem await, recebe um objeto Promise e não a string. O TypeScript acusa o erro, mas se você ignorar, o app quebra em runtime.
Tipar params como number: Segmentos de URL são sempre string. Se a rota é [id] e o valor é 42, params.id é "42" e não 42. Tipe como string e converta manualmente com parseInt ou Number().
Esquecer de tipar searchParams: searchParams pode ser undefined em qualquer campo. Se você acessa searchParams.page sem verificar, pode explodir. Use valores default na desestruturação.
Usar o tipo antigo PageProps do Next.js 14 no 15+: O Next.js 15 mudou a assinatura. Se você copia código de tutorial antigo, o build vai reclamar. Confira sempre a versão do Next.js que tá usando.
Não tipar generateStaticParams: Sem tipagem, você pode retornar objetos com campos errados e o TypeScript não reclama. Tipe o retorno como Promise<Params[]> pra garantir consistência.
Checklist de Page Params Tipados
Domine Next.js + TypeScript na Prática
Tipar page params é só uma peça do quebra-cabeça. No CrazyStack, você constrói um projeto completo com Next.js App Router e TypeScript do zero ao deploy. Cada rota, cada componente, cada API tipada do jeito certo. Você sai com um SaaS funcionando e pronto pra escalar.
Se você quer parar de lutar contra erros de tipo no Next.js e começar a escrever código que se documenta sozinho, esse é o próximo passo.
Continue lendo
Como Tipar Server Actions no Next.js com TypeScript
A tipar Server Actions com 'use server', form data e retornos tipados no Next.js.
Como Tipar Metadata no Next.js com TypeScript
Tipagem completa de Metadata e generateMetadata no Next.js com TypeScript.
Como Usar TypeScript com Next.js App Router
Setup completo de TypeScript no Next.js App Router: page, layout, loading, error e config.
Interface no TypeScript
Quando usar interface