TypeScript : modules et tsconfig
Modules ES
Section intitulée « Modules ES »export interface Client { id: number; nom: string;}export function creerClient(nom: string): Client { return { id: 1, nom };}export default class DepotClients { /* ... */}
// src/index.tsimport DepotClients, { creerClient, type Client } from './clients.js';import type { Client as ClientType } from './clients.js';export type { Client };| Syntaxe | Rôle |
|---|---|
import type { X } |
Importe uniquement un type (effacé à la compilation) |
import { type X, y } |
Mélange type et valeur |
export type { X } |
Exporte un type |
Avec verbatimModuleSyntax, TypeScript impose import type pour les imports qui ne servent que comme types : le code JavaScript produit correspond exactement au code écrit.
Extensions dans les imports
Section intitulée « Extensions dans les imports »Avec "module": "NodeNext" (Node.js, modules ES), les imports relatifs portent l’extension du fichier produit :
import { creerClient } from './clients.js'; // le fichier source est clients.tsOn écrit .js même si le fichier source est en .ts : c’est le nom du fichier après compilation. Avec un outil de construction (Vite, Astro, Next.js) et "moduleResolution": "Bundler", l’extension est facultative. Pour l’exécution directe par Node.js, certaines versions acceptent (et exigent) l’extension .ts ; l’option allowImportingTsExtensions / rewriteRelativeImportExtensions existe selon la version de TypeScript.
Choisir module et moduleResolution
Section intitulée « Choisir module et moduleResolution »| Contexte | module |
moduleResolution |
|---|---|---|
| Application ou bibliothèque Node.js | NodeNext |
NodeNext |
| Application web avec Vite, Astro, Next.js, esbuild | ESNext |
Bundler |
Script exécuté avec tsx |
NodeNext ou ESNext |
NodeNext ou Bundler |
Un mauvais couple produit des erreurs « Cannot find module » alors que le fichier existe.
tsconfig.json commenté
Section intitulée « tsconfig.json commenté »{ "compilerOptions": { "target": "ES2022", "lib": ["ES2023"], "module": "NodeNext", "moduleResolution": "NodeNext",
"strict": true, "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true, "noImplicitOverride": true, "noFallthroughCasesInSwitch": true, "noUnusedLocals": true, "noUnusedParameters": true,
"verbatimModuleSyntax": true, "isolatedModules": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true,
"rootDir": "src", "outDir": "dist", "sourceMap": true, "declaration": true, "baseUrl": ".", "paths": { "@/*": ["src/*"] } }, "include": ["src"], "exclude": ["node_modules", "dist"]}| Option | Rôle |
|---|---|
target |
Version de JavaScript produite |
lib |
API disponibles (DOM pour le navigateur, ES2023 pour Node.js) |
strict |
strictNullChecks, noImplicitAny, strictFunctionTypes, etc. |
noUncheckedIndexedAccess |
Indexation : T | undefined |
exactOptionalPropertyTypes |
x?: number n’accepte pas undefined explicitement |
noImplicitOverride |
Impose le mot-clé override (voir POO : encapsulation et héritage) |
noUnusedLocals, noUnusedParameters |
Signale le code inutilisé |
isolatedModules |
Garantit que chaque fichier peut être transformé seul (outils de construction) |
forceConsistentCasingInFileNames |
Évite les imports dont la casse diffère (Linux est sensible à la casse) |
declaration |
Produit des fichiers .d.ts (bibliothèques) |
paths |
Alias d’import (à doubler dans l’outil de construction) |
strict: true dès le début : l’activer sur un projet existant coûte beaucoup plus cher.
Plusieurs configurations
Section intitulée « Plusieurs configurations »// tsconfig.json (base){ "compilerOptions": { "strict": true, "target": "ES2022" } }
{ "extends": "./tsconfig.json", "include": ["src"], "exclude": ["**/*.test.ts"] }npx tsc -p tsconfig.build.jsonextends hérite d’une configuration ; des préréglages existent (@tsconfig/node24, @tsconfig/strictest, @tsconfig/vite-react).
Fichiers de déclaration .d.ts
Section intitulée « Fichiers de déclaration .d.ts »Un fichier .d.ts décrit les types d’un code JavaScript sans les implémenter.
declare module '*.svg' { const chemin: string; export default chemin;}
interface Window { analytics?: { suivre(evenement: string): void };}
declare const VERSION_APP: string;| Usage | Exemple |
|---|---|
| Importer des fichiers non JavaScript | declare module '*.css' |
| Étendre un type global | interface Window { … } |
| Typer une variable injectée par l’outil de construction | declare const VERSION_APP: string |
Types des bibliothèques
Section intitulée « Types des bibliothèques »| Cas | Solution |
|---|---|
Paquet qui fournit ses types (types dans son package.json) |
Rien à faire |
| Paquet sans types | npm install -D @types/nom-du-paquet (projet DefinitelyTyped) |
| Aucun type disponible | declare module 'nom'; dans un .d.ts (type any), ou écrire ses propres déclarations |
npm install -D @types/node @types/expressnpm ls @types/nodeLes types d’un paquet doivent correspondre à sa version majeure (@types/node à la version de Node.js utilisée).
Dossiers de sortie et .gitignore
Section intitulée « Dossiers de sortie et .gitignore »dist/*.tsbuildinfoNe pas versionner le code compilé ni les fichiers d’information de compilation incrémentale (incremental: true produit .tsbuildinfo).
Projets mixtes : JavaScript et TypeScript
Section intitulée « Projets mixtes : JavaScript et TypeScript »{ "compilerOptions": { "allowJs": true, "checkJs": false, "outDir": "dist" }, "include": ["src"]}allowJs accepte les fichiers .js dans le projet ; checkJs les vérifie aussi (avec des commentaires // @ts-check fichier par fichier au départ). C’est la base d’une migration progressive (voir Dépannage et migration).
Références de projets (monorepo)
Section intitulée « Références de projets (monorepo) »{ "files": [], "references": [{ "path": "./paquets/api" }, { "path": "./paquets/web" }]}npx tsc --buildcomposite: true dans chaque sous-projet permet des compilations incrémentales. Utile à partir de plusieurs paquets liés.
Vérifier la configuration appliquée
Section intitulée « Vérifier la configuration appliquée »npx tsc --showConfig # configuration résolue (après extends)npx tsc --listFiles | head # fichiers inclusnpx tsc --explainFiles | head -30 # pourquoi chaque fichier est inclusnpx tsc --noEmit --extendedDiagnostics # temps de compilationDépannage
Section intitulée « Dépannage »| Symptôme | Piste |
|---|---|
Cannot find module './x' or its corresponding type declarations |
Extension manquante (./x.js) avec NodeNext, ou moduleResolution inadapté |
An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled |
Imports en .ts : option dédiée selon la version, ou écrire .js |
Cannot find module '@/x' |
Alias paths non répété dans l’outil de construction (Vite : resolve.alias) |
'X' is a type and must be imported using a type-only import |
verbatimModuleSyntax : import type |
Could not find a declaration file for module 'x' |
@types/x absent, ou declare module 'x' |
| Fichier non pris en compte | Absent de include, présent dans exclude, extension non reconnue |
error TS6059: File is not under 'rootDir' |
Fichier hors de rootDir : ajuster rootDir ou include |
| La casse des imports échoue seulement sous Linux | forceConsistentCasingInFileNames, corriger les noms |
Ubuntu 24.04 et 26.04 : différences à connaître
Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »Sous Linux, les noms de fichiers sont sensibles à la casse : import './Client' échoue si le fichier s’appelle client.ts. Activer forceConsistentCasingInFileNames.