require vs import en TypeScript : tutoriel pas à pas pour les développeurs perplexes

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

require(x) vs import x : pourquoi c'est un casse-tête récurrent pour les développeurs TypeScript

\n\n

Si vous avez déjà codé en TypeScript et rencontré une erreur comme Cannot use import statement outside a module ou require is not defined, vous n'êtes pas seul. Sur Stack Overflow, la question "The difference between 'require(x)' and 'import x'" cumule des dizaines de milliers de vues. Et ce n'est pas un hasard : la confusion entre les deux systèmes de modules est l'un des pièges les plus fréquents, même pour les développeurs expérimentés.

\n\n

Dans ce tutoriel, nous ne nous contenterons pas de lister les différences. Nous allons passer de l'incompréhension totale à un choix éclairé de la bonne syntaxe. Vous découvrirez comment TypeScript compile votre code, pourquoi require est toujours d'actualité et quand utiliser import.

\n\n

1. Contexte historique : d'où viennent ces deux systèmes

\n\n

Pour comprendre la différence, il faut remonter dans l'histoire de JavaScript. À l'origine, Node.js n'avait pas de système de modules intégré. Les développeurs ont créé CommonJS — une méthode synchrone pour inclure des modules via require(). Cette approche fonctionne côté serveur, mais pas pour les navigateurs, qui nécessitent un chargement asynchrone.

\n\n

Plus tard, le standard ES Modules (ESM) est apparu — la syntaxe modulaire officielle d'ECMAScript. TypeScript, en tant que surcouche de JS, prend en charge les deux options. Mais c'est là que la confusion commence : vous écrivez import, et le compilateur le transforme en require — ou l'inverse.

\n\n

2. Syntaxe : les principales différences

\n\n

Détaillons à quoi ressemblent les deux approches.

\n\n

CommonJS (require)

\n\n
// Import d'un module entier\nconst fs = require('fs');\n\n// Import d'une partie d'un module (destructuration)\nconst { readFile, writeFile } = require('fs');\n\n// Export\nmodule.exports = { myFunction, myVariable };\nexports.myFunction = () => { ... };
\n\n

ES Modules (import)

\n\n
// Import d'un module entier\nimport fs from 'fs';\n\n// Import d'exports nommés\nimport { readFile, writeFile } from 'fs';\n\n// Import de tout comme un objet\nimport * as fs from 'fs';\n\n// Export\nexport const myVariable = 42;\nexport function myFunction() { ... }\nexport default class MyClass { }
\n\n

À première vue, seule la syntaxe diffère. Mais creusons un peu plus.

\n\n

3. Import statique vs dynamique

\n\n

C'est la différence clé qui impacte le fonctionnement de votre code.

\n\n
    \n
  • require — dynamique. Vous pouvez l'appeler n'importe où, dans une condition ou une fonction. Le module est chargé au moment de l'appel.
  • \n
  • import — statique. Les imports sont résolus à la compilation, avant l'exécution du code. Ils doivent toujours être en haut du fichier.
  • \n
\n\n

Exemple de require dynamique :

\n\n
let myModule;\nif (process.env.NODE_ENV === 'production') {\n  myModule = require('./production-config');\n} else {\n  myModule = require('./dev-config');\n}
\n\n

Une telle astuce ne fonctionne pas avec import — cela génère une erreur de syntaxe. Mais il existe import() dynamique (qui retourne une Promise) :

\n\n
if (condition) {\n  const module = await import('./some-module');\n  module.doSomething();\n}
\n\n

4. Comment TypeScript compile les modules

\n\n

Tout dépend du paramètre module dans tsconfig.json. Voici les options principales :

\n\n
    \n
  • "module": "commonjs" — votre import sera transformé en require. Le code fonctionnera dans Node.js sans configuration supplémentaire.
  • \n
  • "module": "esnext" — import reste tel quel. Idéal pour les navigateurs modernes ou les bundlers (Webpack, Vite).
  • \n
  • "module": "node16" ou "nodenext" — TypeScript détecte automatiquement

Blogs

Book Recommendations