Next.js

Next.js + TypeScript : configuration et bonnes pratiques (2026)

Publié le 11 February 2026 — 3 min de lecture
En bref

TypeScript est incontournable dans un projet Next.js sérieux. Ce guide vous montre comment configurer TypeScript dans Next.js, typer les composants, les props, les Server Actions et les APIs pour un code robuste et maintenable.

TypeScript est activé par défaut dans Next.js depuis la version 13. En 2026, développer un projet Next.js sans TypeScript est une erreur — les gains en maintenabilité et en sécurité de type valent largement le coût d’apprentissage. Voici la configuration optimale et les patterns à connaître.

Configuration tsconfig.json pour Next.js

Next.js génère un tsconfig.json optimal. Les options les plus importantes :

{
  "compilerOptions": {
    "target": "ES2017",
    "lib": ["dom", "dom.iterable", "esnext"],
    "strict": true,                    // Activez TOUJOURS strict mode
    "noUncheckedIndexedAccess": true,  // Sécurise l'accès aux tableaux
    "moduleResolution": "bundler",
    "paths": {
      "@/*": ["./src/*"]              // Import alias
    }
  }
}

Le strict: true active 8 règles TypeScript strictes dont noImplicitAny et strictNullChecks. Ne le désactivez jamais — il protège des bugs les plus courants.

Typer les composants et les props

// Interface pour les props
interface ArticleCardProps {
  title: string;
  excerpt: string;
  publishedAt: Date;
  author: { name: string; avatar?: string };
  tags: string[];
  onTagClick?: (tag: string) => void; // prop optionnelle
}

export function ArticleCard({ title, excerpt, author, onTagClick }: ArticleCardProps) {
  return (
    <article>
      <h2>{title}</h2>
      <p>{excerpt}</p>
      {author.avatar && <img src={author.avatar} alt={author.name} />}
    </article>
  );
}

Typer les routes et les paramètres

// app/blog/[slug]/page.tsx
interface PageProps {
  params: { slug: string };
  searchParams: { page?: string; sort?: 'asc' | 'desc' };
}

export default async function ArticlePage({ params, searchParams }: PageProps) {
  const article = await getArticle(params.slug);
  const page = parseInt(searchParams.page ?? '1', 10);
  // ...
}

Typer les appels fetch et les données API

interface Article {
  id: number;
  title: string;
  slug: string;
  content: string;
  publishedAt: string; // ISO string depuis l'API
  author: { id: number; name: string };
}

async function getArticle(slug: string): Promise<Article> {
  const res = await fetch(`/api/articles/${slug}`);
  if (!res.ok) throw new Error(`Article not found: ${slug}`);
  return res.json() as Promise<Article>;
}

// Avec Zod pour la validation runtime
import { z } from 'zod';
const ArticleSchema = z.object({
  id: z.number(),
  title: z.string().min(1).max(200),
  slug: z.string(),
});
type Article = z.infer<typeof ArticleSchema>;
const article = ArticleSchema.parse(await res.json()); // valide ET type

Typer les Server Actions

"use server";
import { z } from 'zod';

const CreateArticleSchema = z.object({
  title: z.string().min(1, 'Le titre est requis'),
  content: z.string().min(50),
});

type ActionResult = { success: true; id: number } | { success: false; errors: Record<string, string[]> };

export async function createArticle(formData: FormData): Promise<ActionResult> {
  const raw = { title: formData.get('title'), content: formData.get('content') };
  const result = CreateArticleSchema.safeParse(raw);
  if (!result.success) return { success: false, errors: result.error.flatten().fieldErrors };
  const article = await db.article.create({ data: result.data });
  return { success: true, id: article.id };
}

Utilitaires TypeScript utiles

// Partial — toutes les propriétés optionnelles
type UpdateArticle = Partial<Article>;

// Pick — seulement certaines propriétés
type ArticleSummary = Pick<Article, 'id' | 'title' | 'slug'>;

// Omit — tout sauf certaines propriétés
type CreateArticle = Omit<Article, 'id' | 'publishedAt'>;

// Record — objet avec clés et valeurs typées
type LocaleMessages = Record<'fr' | 'en' | 'es', string>;

// NonNullable — exclut null et undefined
type SafeUser = NonNullable<User | null>; // = User

ESLint TypeScript

Next.js inclut ESLint préconfigurée. Ajoutez les règles TypeScript strictes dans .eslintrc.json :

{
  "extends": ["next/core-web-vitals", "next/typescript"],
  "rules": {
    "@typescript-eslint/no-explicit-any": "error",
    "@typescript-eslint/no-unused-vars": "error",
    "@typescript-eslint/prefer-nullish-coalescing": "warn"
  }
}
W
Rédigé par
WebEngine
Développeur web freelance à Paris spécialisé WordPress, WooCommerce et SEO technique depuis 2010. 13 avis vérifiés · Note 5/5. Chaque site livré atteint un score PageSpeed mobile supérieur à 90.

Un projet en tête ?

Devis gratuit sous 48h, sans engagement.

Demander un devis gratuit