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.
- Passo 1 - Defina a interface dos params: Crie um type que espelha exatamente os segmentos dinâmicos da sua rota. Se a pasta é [slug], o type tem slug: string. Se é [category]/[id], o type tem ambos.
- Passo 2 - Use o tipo PageProps do Next.js 15+: Importe ou defina o tipo onde params e searchParams são Promise. Essa é a assinatura correta no App Router atual.
- Passo 3 - Faça await nos params dentro da função: Como params agora é Promise, use const { slug } = await params no corpo da função. Não desestruture direto na assinatura.
- Passo 4 - Tipe searchParams como Record opcional: searchParams pode ter qualquer query string. Tipe como Record
ou crie um type específico pro que você espera. - Passo 5 - Implemente generateStaticParams tipado: Retorne um array de objetos que batem com o tipo dos seus params. O TypeScript valida que você tá gerando as rotas certas.
- Passo 6 - Teste no build: Rode next build pra garantir que não tem erro de tipo escondido. O build do Next.js valida a tipagem de todas as rotas de uma vez.
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
Checklist de Page Params Tipados
- Criou um type Params que espelha os segmentos dinâmicos da rota
- Params e searchParams tipados como Promise (Next.js 15+)
- Faz await nos params dentro do corpo da função
- SearchParams com valores default na desestruturação
- generateStaticParams com tipo de retorno explícito
- Params sempre tipados como string (nunca number direto)
- Catch-all routes com slug tipado como string[]
- Build passa sem erros de tipo nas rotas dinâmicas
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.