Tipar Layout no Next.js com TypeScript
Domine a tipagem de layouts no Next.js. De LayoutProps e children até parallel routes e metadata, tudo com exemplos que você aplica agora.
Por que isso é importante
Tipar Layout no Next.js com TypeScript. Domine a tipagem de layouts no Next.js. De LayoutProps e children até parallel routes e metadata, tudo com exemplos que você aplica agora.
O Que São Layouts e Templates no Next.js
No App Router do Next.js, layout.tsx é um componente que envolve as páginas de um segmento de rota. Ele recebe children como prop e renderiza ao redor de cada página. O detalhe: o layout NÃO remonta quando você navega entre páginas filhas. Ele persiste.
Já o template.tsx parece um layout, mas remonta a cada navegação. Isso é útil quando você quer animar transições de página ou resetar estado entre rotas.
O RootLayout é especial. Ele fica no app/layout.tsx e é obrigatório. Todo projeto Next.js precisa de um. Ele define as tags html e body, e envolve absolutamente tudo.
TypeScript entra pra garantir que esses componentes recebem as props certas. Se você esquece de declarar children, por exemplo, o layout compila mas renderiza vazio. Com tipagem explícita, esse erro vira um alerta no editor.
Como Tipar Layout e Template Passo a Passo
Vamos montar layouts tipados do zero. Cada passo cobre um cenário que você vai encontrar em projetos reais.
children em layouts é sempre React.ReactNode. Declare explicitamente: { children: React.ReactNode }.import type { Metadata } from 'next' pra tipar metadata e trabalhar com os tipos oficiais.<html> e <body>. Tipe as props e garanta que children está dentro do body.params. Tipe como { params: Promise<{ slug: string }> } no Next.js 15+ ou { params: { slug: string } } em versões anteriores.@modal, @sidebar. Cada slot é uma prop React.ReactNode adicional.export const metadata: Metadata = { ... } pra ter autocomplete de todas as propriedades de SEO.Exemplos Práticos de Layout Tipado
Código real que você copia e adapta pro seu projeto.
RootLayout Tipado Completo
// app/layout.tsx
import type { Metadata } from 'next';
// Metadata tipada com autocomplete completo
export const metadata: Metadata = {
title: {
default: 'Meu App',
template: '%s | Meu App',
},
description: 'Descrição do app',
openGraph: {
type: 'website',
locale: 'pt_BR',
},
};
// Props do RootLayout
interface RootLayoutProps {
children: React.ReactNode;
}
export default function RootLayout({ children }: RootLayoutProps) {
return (
<html lang="pt-BR">
<body>
{children}
</body>
</html>
);
}
Layout com Params Dinâmicos
// app/blog/[slug]/layout.tsx
// Next.js 15+ usa Promise nos params
interface BlogLayoutProps {
children: React.ReactNode;
params: Promise<{ slug: string }>;
}
export default async function BlogLayout({
children,
params,
}: BlogLayoutProps) {
const { slug } = await params;
return (
<div>
<nav>Blog: {slug}</nav>
<main>{children}</main>
</div>
);
}
// Versoes anteriores ao Next.js 15
// interface BlogLayoutProps {
// children: React.ReactNode;
// params: { slug: string };
// }
Layout com Parallel Routes (Slots)
// app/dashboard/layout.tsx
// Parallel routes: @analytics, @team, @notifications
interface DashboardLayoutProps {
children: React.ReactNode;
analytics: React.ReactNode; // Slot @analytics
team: React.ReactNode; // Slot @team
notifications: React.ReactNode; // Slot @notifications
}
export default function DashboardLayout({
children,
analytics,
team,
notifications,
}: DashboardLayoutProps) {
return (
<div className="grid grid-cols-12 gap-4">
<aside className="col-span-3">
{team}
{notifications}
</aside>
<main className="col-span-6">{children}</main>
<section className="col-span-3">{analytics}</section>
</div>
);
}
Template vs Layout: Diferença na Tipagem
// app/dashboard/template.tsx
// Template remonta a cada navegacao (diferente do layout)
interface DashboardTemplateProps {
children: React.ReactNode;
}
export default function DashboardTemplate({
children,
}: DashboardTemplateProps) {
// Esse useEffect roda a cada navegacao
// porque template remonta sempre
return (
<div className="animate-fadeIn">
{children}
</div>
);
}
// A tipagem de props e identica ao layout
// A diferenca e no comportamento: template remonta, layout persiste
Metadata Dinâmica com generateMetadata
// app/blog/[slug]/layout.tsx
import type { Metadata } from 'next';
// generateMetadata recebe os mesmos params do layout
interface MetadataProps {
params: Promise<{ slug: string }>;
}
export async function generateMetadata(
{ params }: MetadataProps
): Promise<Metadata> {
const { slug } = await params;
const post = await getPost(slug);
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
type: 'article',
publishedTime: post.date,
},
};
}
Em todos os exemplos, a tipagem pega erros antes de rodar. Se você esquecer de declarar um slot de parallel route ou passar o tipo errado em params, o editor avisa na hora.
Erros Comuns ao Tipar Layouts
Deslizes que geram bugs silenciosos
Esquecer de declarar children na interface: o layout compila, mas renderiza vazio. Sem children tipado, o TypeScript não reclama e você fica procurando o bug na rota errada.
Confundir layout com template: os dois recebem children, mas layout persiste e template remonta. Se você precisa de animação entre páginas, use template. Se precisa manter estado, use layout.
Tipar params como objeto direto no Next.js 15+: a partir do Next.js 15, params virou Promise. Se você tipar como objeto síncrono, o TypeScript compila mas o valor vem como Promise não resolvida.
Não tipar slots de parallel routes: cada pasta @nome na rota vira uma prop no layout. Se você não declara na interface, o slot é ignorado e a seção some da página.
Usar any em children: children deveria ser React.ReactNode. Usar any desliga a checagem e qualquer coisa passa sem aviso, incluindo valores que não são renderizáveis.
Checklist de Layout Tipado no Next.js
Monte Layouts Profissionais na Prática
Layouts tipados são a base de qualquer aplicação Next.js séria. No CrazyStack, você constrói um projeto inteiro com App Router, layouts aninhados, parallel routes e metadata dinâmica. Tudo tipado com TypeScript do primeiro ao último arquivo.
Chega de layout quebrado em produção. Você termina o curso com uma aplicação completa rodando e pronta pra usar como portfólio.
Continue lendo
Como Tipar Middleware no Next.js com TypeScript
A tipar middleware, NextRequest e NextResponse no Next.js.
Como Tipar Page Params no Next.js com TypeScript
Tipagem correta de params e searchParams em pages do Next.js.
Como Usar Generics no TypeScript
Domine generics no TypeScript e crie código reutilizável e tipado.
Interface no TypeScript
Quando usar interface