Aller au contenu principal
Retour au blog
Web

TypeScript en mode strict : pourquoi et comment migrer

Activer le mode strict de TypeScript intimide. C'est pourtant le meilleur ROI sur la qualité d'une base de code. Méthode de migration progressive sans bloquer l'équipe, et bénéfices mesurés après 5 ans en strict mode chez Krealabs.

11 min826 mots

Le mode strict de TypeScript active une série de checks (strictNullChecks, noImplicitAny, noUncheckedIndexedAccess, etc.) qui transforment radicalement la fiabilité d'une base de code. Encore faut-il pouvoir migrer un projet existant sans bloquer la livraison de features. Chez Krealabs, tous nos projets sont en strict mode depuis 2020, et on a accompagné une douzaine de clients dans la migration de leur base de code non-stricte. Voici ce qu'on a appris : ce que strict change vraiment, comment migrer progressivement, et les bénéfices mesurables qu'on observe après 1-2 ans.

01Ce que strict change vraiment

Le mode strict force à gérer explicitement les cas null/undefined (strictNullChecks), les types implicites any (noImplicitAny), les fonctions qui ne couvrent pas tous les cas (strictFunctionTypes), et les méthodes appelées sur des valeurs potentiellement nulles (alwaysStrict). Sur une base de code typique de 50k lignes, l'activation révèle 100 à 500 bugs latents — la plupart silencieux en production : variables undefined dans certains edge cases, propriétés d'objet manquantes, fonctions qui retournent parfois undefined sans que personne ne le sache. Les développeurs qui ont vécu une migration n'imaginent plus revenir en arrière.

02L'option qui change tout : noUncheckedIndexedAccess

C'est l'option la moins connue et la plus impactante. Sans elle, `array[0]` est typé comme le type du tableau (T), pas T | undefined. Or, l'index 0 d'un tableau vide est undefined ! Avec noUncheckedIndexedAccess, TypeScript force à vérifier l'existence avant utilisation. C'est verbeux au début mais ça élimine une catégorie entière de bugs `TypeError: Cannot read property X of undefined`.

// Sans noUncheckedIndexedAccess
const first = users[0]
console.log(first.name) // Crash si users est vide

// Avec noUncheckedIndexedAccess
const first = users[0]
console.log(first.name) // ❌ TypeScript : first peut être undefined
console.log(first?.name) // ✅ OK
if (first) console.log(first.name) // ✅ OK

03Activer progressivement, par dossier

Pas besoin de tout activer d'un coup. Commencez par noImplicitAny (souvent gérable, force à typer les paramètres), puis strictNullChecks (le plus impactant, force à gérer les null/undefined), puis le reste. Vous pouvez aussi configurer strict par dossier en utilisant plusieurs tsconfig.json avec extends. Sur les projets Next.js, on commence souvent par strict sur les API routes et utilities, puis on étend aux composants UI.

// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    // ou progressif :
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true
  }
}

// tsconfig.strict.json (pour un sous-dossier audité)
{
  "extends": "./tsconfig.json",
  "compilerOptions": { "strict": true, "noUncheckedIndexedAccess": true },
  "include": ["./src/api/**/*", "./src/lib/**/*"]
}

04Outils pour la migration automatisée

ts-migrate de Airbnb automatise une partie (ajoute des annotations `// @ts-expect-error` aux endroits qui posent problème, type les paramètres any en `any` explicite, etc.). Pour les erreurs restantes, utilisez @ts-expect-error avec un commentaire TODO daté, plutôt que @ts-ignore. La différence : @ts-expect-error échoue si l'erreur n'existe plus (force le nettoyage), @ts-ignore est silencieux pour toujours. ESLint avec @typescript-eslint/ban-ts-comment peut interdire @ts-ignore. Combiner avec un fichier `TYPESCRIPT_DEBT.md` qui liste les zones à reprendre.

05Bénéfices mesurés après 1-2 ans

Sur les projets clients où on a piloté la migration en 2023-2024, on a mesuré : 1) Réduction de 30 à 50% des bugs de production liés à `undefined` ou `null` (rapport Sentry). 2) Refactorings 3x plus rapides (changer un type propage les erreurs partout, on sait exactement quoi mettre à jour). 3) Onboarding des nouveaux développeurs accéléré (les types servent de documentation vivante). 4) Moins de tests unitaires à écrire pour cas null/undefined (le compilateur les attrape). Coût initial : 2-4 semaines selon la taille du codebase. Retour sur investissement : moins d'un an.

06Combiner avec Zod et runtime validation

TypeScript est purement statique : il disparaît à la compilation. Pour valider les données qui ENTRENT dans votre app (API responses, formulaires utilisateur, query params), utilisez une bibliothèque de runtime validation comme Zod, Valibot ou TypeBox. Zod génère le type TypeScript automatiquement à partir du schéma, donc une seule source de vérité. Pattern qu'on utilise chez Krealabs partout : valider les payloads d'API avec Zod, le type est inféré, plus aucun cast manuel.

import { z } from 'zod'

const UserSchema = z.object({
  id: z.string().uuid(),
  email: z.string().email(),
  age: z.number().int().positive().optional(),
})

type User = z.infer<typeof UserSchema> // Type généré

// Validation runtime
const user = UserSchema.parse(req.body) // Throw si invalide
// user est maintenant typé ET validé

07Les libs tierces non-strict : que faire

Le frein principal à strict mode dans un projet existant : les bibliothèques tierces dont les types sont mal écrits ou pas à jour. Solutions : 1) Préférer les libs maintenues avec des types corrects (TanStack Query, Zod, Prisma — excellents). 2) Pour les libs avec mauvais types, écrire un wrapper typé qui isole l'incohérence. 3) En dernier recours, declare module 'lib-name' pour overrider les types. 4) Contribuer aux types upstream si possible (DefinitelyTyped) — geste citoyen et ça résout pour tout le monde.

En résumé

Tous nos projets Krealabs démarrent en strict mode + noUncheckedIndexedAccess. C'est non négociable : le coût initial est minime, le bénéfice sur 2-3 ans est énorme. Si vous héritez d'une base de code non stricte, la migration vaut largement l'investissement — mais demande du temps dédié, pas seulement quelques heures volées entre deux features. Si vous voulez accompagnement pour migrer votre base de code TypeScript vers strict, c'est exactement le type de mission qu'on adore.

TypeScript
Typage
Qualité
Refactoring
Web
Strict mode
Maxime Dubois

Écrit par

Maxime Dubois

Co-fondateur · Krealabs

Découvrir l'équipe

À propos de cet article

Rédigé par

Maxime Dubois

Co-fondateur · Krealabs

Méthodologie

Rédigé à partir de notre travail d'agence et de la documentation officielle des outils cités. Pas d'IA générative pour le fond éditorial.

Publié le
Parlons projet

Un sujet à creuser ensemble ?

Si cet article t'a parlé et que tu as un projet en cours (ou naissant), écris-nous — premier échange offert.