01 - tsconfig en profondeur
Ce que tu vas apprendre
- Les options
strictet ce qu'elles activent individuellement moduleResolution,module,target: le trio qui embrouille tout le mondepathspour les alias d'importverbatimModuleSyntaxet les imports de types- Un tsconfig recommande pour un projet en 2026
Prerequisites
Avoir lu l'introduction de cette serie.
Le fichier que personne ne lit
La plupart des devs copient un tsconfig d'un projet précédent ou d'un template sans comprendre ce qu'il fait. Ca fonctionne jusqu'au jour ou un import echoue, ou un type se comporte bizarrement, ou la compilation est anormalement lente.
Le tsconfig a plus de 100 options. On ne va pas toutes les couvrir. On va se concentrer sur celles qui ont un impact réel sur ton code.
strict : le mode non-negociable
strict: true active un ensemble d'options de vérification :
json{
"compilerOptions": {
"strict": true
}
}
Ce que ca active :
| Option | Ce qu'elle fait |
|---|---|
strictNullChecks |
null et undefined ne sont plus assignables a tout |
strictFunctionTypes |
Les paramètres de fonctions sont contravariants |
strictBindCallApply |
Verifie les types de bind, call, apply |
strictPropertyInitialization |
Les propriétés de classes doivent etre initialisees |
noImplicitAny |
Refuse les any implicites |
noImplicitThis |
Refuse this non type |
useUnknownInCatchVariables |
catch (err) a le type unknown |
alwaysStrict |
Ajoute "use strict" partout |
exactOptionalPropertyTypes |
Distingue prop?: T de prop: T | undefined |
Mon avis : strict: true dans tout nouveau projet, sans exception. Si tu herites d'un projet sans strict, l'article sur la migration couvre la transition progressive.
module et moduleResolution
Le duo le plus confus du tsconfig. module definit le format des modules en sortie. moduleResolution definit comment TypeScript resout les imports.
module
json{
"compilerOptions": {
"module": "ESNext"
}
}
Les valeurs courantes en 2026 :
"ESNext"— modules ES natifs (import/export). Le standard."NodeNext"— modules Node.js (supporte ESM et CJS selon le package.json)"CommonJS"— l'ancien format Node.js (require/module.exports)
Si tu utilises Bun, Vite, ou un bundler moderne : "ESNext". Si tu fais du Node.js pur avec ESM : "NodeNext".
moduleResolution
json{
"compilerOptions": {
"moduleResolution": "bundler"
}
}
Les valeurs qui comptent :
"bundler"— pour les projets avec un bundler (Vite, esbuild, Bun). Supporte les imports sans extension, lespackage.jsonexports, et les alias."nodenext"— pour du Node.js pur. Exige les extensions dans les imports (.js)."node"— l'ancien mode Node.js. Evite-le dans les nouveaux projets.
Si tu utilises Bun ou Vite, "bundler" est le bon choix. Si tu fais du Node.js ESM sans bundler, "nodenext".
target
Le niveau ECMAScript de la sortie :
json{
"compilerOptions": {
"target": "ES2022"
}
}
target déterminé quelles features JavaScript sont conservees et lesquelles sont transpilees. ES2022 est un bon défaut en 2026 : tous les runtimes modernes (Node 18+, Bun, navigateurs recents) le supportent.
Si tu utilises Bun, tu peux mettre "ESNext" — Bun supporte tout.
paths : les alias d'import
Les alias remplacent les chemins relatifs longs par des prefixes :
json{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@api/*": ["src/api/*"],
"@types/*": ["src/types/*"]
}
}
}
typescript// Avant
import { User } from "../../../types/user"
// Apres
import { User } from "@types/user"
Les paths sont resolus par TypeScript a la compilation. Ton bundler (Vite, Bun, esbuild) doit avoir la meme configuration pour que les imports fonctionnent au runtime.
Sur paltemps.fr, le monorepo utilise @api/, @shared/, @blog/ pour les imports entre packages.
verbatimModuleSyntax
Depuis TypeScript 5.0, cette option remplace isolatedModules et importsNotUsedAsValues :
json{
"compilerOptions": {
"verbatimModuleSyntax": true
}
}
Elle force l'utilisation de import type pour les imports qui ne sont que des types :
typescript// ❌ Erreur avec verbatimModuleSyntax
import { User } from "./types" // si User est seulement un type
// ✅ Correct
import type { User } from "./types"
// ✅ Import mixte
import { createUser, type User } from "./users"
Pourquoi c'est important : les bundlers (esbuild, swc, Bun) ne font pas d'analyse de types. Ils ne savent pas si User est une valeur ou un type. import type leur dit explicitement de supprimer cet import au build.
skipLibCheck
json{
"compilerOptions": {
"skipLibCheck": true
}
}
skipLibCheck: true ignore les erreurs de type dans les fichiers .d.ts de node_modules. Ca accéléré la compilation et évité les erreurs causees par des types incompatibles entre deux libs.
Mon avis : toujours true. Les erreurs dans les types des libs ne sont pas ton problème. Si tu les actives, tu passes du temps a debug des conflits dans @types/node vs @types/express qui n'affectent pas ton code.
noUncheckedIndexedAccess
Une option sous-estimee :
json{
"compilerOptions": {
"noUncheckedIndexedAccess": true
}
}
Elle ajoute | undefined au type de retour des acces par index :
typescriptconst arr = [1, 2, 3]
const first = arr[0] // type: number | undefined (pas number)
const dict: Record<string, number> = { a: 1 }
const val = dict["b"] // type: number | undefined (pas number)
Sans cette option, TypeScript pretend que l'acces par index retourne toujours une valeur. Avec, il te force a vérifier. C'est plus strict mais ca attrape des bugs d'acces hors limites.
Mon tsconfig recommande
Pour un projet Bun/Vite en 2026 :
json{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"verbatimModuleSyntax": true,
"noUncheckedIndexedAccess": true,
"noEmit": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*", "types/**/*"],
"exclude": ["node_modules", "dist"]
}
noEmit: true parce que Bun ou le bundler s'occupe de la transpilation. TypeScript ne sert qu'au type checking.
Résumé
strict: trueest non-negociable — il active 8+ verifications de sécuritémoduledefinit le format de sortie,moduleResolutiondefinit la résolution des imports —"ESNext"+"bundler"pour les projets modernesverbatimModuleSyntaxforceimport typepour les imports de types — requis pour les bundlersskipLibCheck: trueaccéléré la compilation et évité les conflits dans node_modulesnoUncheckedIndexedAccessajoute| undefinedaux acces par index — plus strict mais plus sur
Article précédent : 00 - Introduction
Article suivant : 02 - Zod : validation runtime et inference