devstory

Module dans TypeScript

  1. Qu'est-ce que c'est un module ?
  2. Des idées sur les modules avant ES6
  3. Le mot-clef export
  4. Le mot-clef import
  5. Le mot-clef module/namespace
  6. L'utilisation du module dans HTML

1. Qu'est-ce que c'est un module ?

À partir de la spécification ECMAScript 2015 (ES6), JavaScript dispose d'un nouveau concept qui est module. TypeScript partage également ce concept.
Les modules avec des ressources de code ne sont utilisés que dans une portée fermée, pas dans la portée globale. Cela signifie que les variables, fonctions, classes, .. déclarées dans le module ne seront pas visibles à l'extérieur du module sauf si elles sont explicitement exportées via l'expression d'export. De plus, pour utiliser une ressource exportée d'un autre module, vous devez l'importer explicitement via l'expression d'import.
Les programmeurs ont tendance à organiser chaque fichier sous forme de module, ce qui facilite la gestion du code. Bien que vous puissiez définir deux modules ou plus dans un fichier avec le mot-clé module ou namespace. Si un fichier n'inclut pas les mots-clefs module et namespace, cela signifie qu'il s'agit d'un module unique.

2. Des idées sur les modules avant ES6

L'idée d'un module existe depuis longtemps en JavaScript, mais ce n'est qu'avec ES6 (2015) qu'il a été pris en charge au niveau du langage en ajoutant de nouveaux mots-clefs comme import, export et module. Avant la version ES6 (2015), de nombreuses spécifications de modules ont été créées telles que CommonJS, AMD, UMD, .. leur but est d'établir des conventions sur l'écosystème des modules. Depuis lors, de nombreuses bibliothèques ont mis en œuvre les spécifications ci-dessus.
Un extrait de code qui crée et utilise le module conformément aux normes CommonJS :
// package/lib is a dependency we require
var lib = require( "package/lib" );

// behaviour for our module
function foo(){
    lib.log( "hello world!" );
}
// export (expose) foo to other modules
exports.foo = foo;
Parfois, les anciennes spécifications et bibliothèques risquent de nous déconcerter, comme si nous nous égarons dans un labyrinthe. L'article ci-dessous aborde l'historique des modules en JavaScript, ce qui vous propose une vue d'ensemble du module et permet d'éviter de perdre du temps avec des bibliothèques obsolètes :

3. Le mot-clef export

A l'instar de JavaScript, le code de TypeScript a une portée globale par défaut. Si vous avez plusieurs fichiers dans un projet, les variables, fonctions, ... qui sont écrits dans un fichier, ils peuvent être reconnus et utilisés dans d'autres fichiers. Pour mieux comprendre, observer cet exemple :
file1.ts
var greeting : string = "Hello World!";

function sayHello(name: string) {
    console.log(`Hello $name`);
}
file2.ts
sayHello('Tom');
console.log(greeting);
// Set new value to greeting
greeting = 'Hi';
Dans l'exemple ci-dessus, le fichier file1.ts définit la variable de greeting et la fonction sayHello(string), qui peuvent être reconnues et utilisées dans le fichier file2.ts. De plus, la variable de greeting peut se voir attribuer une nouvelle valeur n'importe où dans l'application, ce qui peut entraîner des conflits ou des erreurs pour l'application.
Le mot-clef export
Le mot-clef export est utilisé pour empêcher la "portée globale par défaut" (default global scope) du code TypeScript. L'utilisation : placer le mot-clé export devant les "choses" définies au niveau top-lever du fichier.
On réécrit le code dans file1.ts avec la participation du mot-clef export :
file1.ts (*)
export var greeting : string = "Hello World!";

export function sayHello(name: string) {
    console.log(`Hello $name`);
}
Après la modification du code, file1.ts est considéré comme un module.
Le compilateur va signaler maintenant une erreur sur file2.ts :
file2.ts (*)
sayHello('Tom');  // ERROR: Cannot find name 'sayHello'.

console.log(greeting);  // ERROR: Cannot find name 'greeting'.
// Set new value to greeting
greeting = 'Hi'; // ERROR: Cannot find name 'greeting'.

4. Le mot-clef import

Le mot-clef import est utilisé pour importer des "choses" définies avec le mot-clef export d'un certain fichier.
La syntaxe :
// Import multiple 'things':
import { export_name1, export_name2 } from "file_path_without_extension"

// Import only one 'thing':
import  export_name1 from "file_path_without_extension"

// Import all 'things' into a variable.
import  * as variable_name from "file_path_without_extension"

// Import with alias name:
import { export_name1 as alias_name1, export_name2 } from "file_path_without_extension"
Par exemple :
file1.ts
export var greeting : string = "Hello World!";

export function sayHello(name: string) {
    console.log(`Hello $name`);
}
file2.ts
import {sayHello, greeting} from './file1';

sayHello('Tom');   
console.log(greeting);
Par exemple : Importer tout dans une variable :
file2b.ts
import * as f1 from './file1';

f1.sayHello('Tom');   
console.log(f1.greeting);
Par exemple : Importer avec un nom d'alias :
file2c.ts
import {sayHello as hello, greeting} from './file1';

hello('Tom');   
console.log(greeting);

5. Le mot-clef module/namespace

Dans JavaScript ES6, le mot-clef module est utilisé pour définir un module, cela vous permet de définir plusieurs modules dans un fichier. TypeScript utilise le mot-clef namespace avec une syntaxe et des objectifs similaires.
Remarque : Les mots clefs "module" et "namespace" peuvent être utilisés dans TypeScript avec une syntaxe et une utilisation similaires. Cependant, la documentation TypeScript déconseille l'utilisation du mot-clef "module" dans le code TypeScript. Il ne doit être utilisé que dans du code JavaScript.
Dans TypeScript, le mot-clef "namespace" est légèrement plus fort que le mot-clef "module". Vous pouvez définir un module sur plusieurs fichiers avec le mot-clef "namespace" et utiliser le drapeau "--outFile" si vous voulez qu'ils soient regroupés dans un seul fichier au moment de la compilation.
Dans l'exemple ci-dessous, on définit 2 modules dans un fichier.
my_common_libs.ts
export namespace MyMathLib  {
    export function minus(a: number, b: number)  {
        return a - b;
    }
    export function sum(a: number, b: number)  {
        return a + b;
    }
}

export namespace MyStringLib {
    export var LIB_INFO = "String Lib";
    var AUTHOR = 'tran'; // Use only in module.

    export function toUpperCase(s:string)  {
        return s.toUpperCase;
    }
}
Dans un autre fichier, on utilise le module ci-dessus.
use_my_common_libs_ex1.ts
import {MyMathLib, MyStringLib} from './my_common_libs';

let value = MyMathLib.minus(1, 2);
console.log(`value = ${value}`);
console.log('MyStringLib info: ' + MyStringLib.LIB_INFO);
Consulter l'article détaillé sur les TypeScript Namespaces :

6. L'utilisation du module dans HTML

En règle générale, la plupart des navigateurs modernes prennent en charge les modules et ont un Module Loader intégré, on n'a donc pas besoin d'utiliser de bibliothèques supplémentaires. Le code suivant est un moyen d'indiquer au navigateur que cette source JavaScript est un module :
test.html
<html>
   <head>
      <!-- Important: type='module' -->
      <script type="module" src="./dist/file2.js"></script>
   </head>
   <body>
      <h3>To test, you need to run this file on an HTTP or HTTPS server.
         And see the results on the browser Console.
      </h3>
   </body>
</html>
Pour tester avec succès l'exemple ci-dessus, vous devez exécuter le fichier test.html sur un serveur HTTP ou HTTPS et afficher les résultats dans la fenêtre de la Console du navigateur.