Utiliser export et import dans Angular

Vous avez sûrement repéré les mots-clé export et import dans l’application Angular que nous avons créée. À quoi servent-t-ils et comment les utiliser ?

Les modules et le scope privé

Les mots-clé export et import sont liés aux “modules”, une fonctionnalité disponible à partir de JavaScript ES6 et également dans Typescript. Un module est simplement un fichier dont le scope est privé.

Supposons qu’on ait un premier fichier dans lequel on déclare une variable firstName :

// fichier-a.ts
const firstName = 'James';

Essayons d’afficher cette variable firstName dans un deuxième fichier, qui est chargé juste après le premier :

// fichier-b.ts
console.log(firstName);   // ERREUR

Ça ne fonctionnera pas, car firstName n’est visible que dans le fichier, ou plutôt le “module”, où elle a été déclarée. Cela s’oppose au comportement de l’ancien JavaScript (ES5), où toute variable déclarée à la racine d’un fichier se retrouve dans le scope global.

Pour communiquer entre eux, les différents fichiers d’une application TypeScript ou JavaScript ES6 doivent utiliser les mots-clé export et import.

1) On commence par exporter le ou les symbole(s) qu’on veut rendre visibles à l’extérieur de leur fichier, en les précédant du mot-clé export :

// fichier-a.ts
export const firstName = 'James';

2) Puis on importe le ou les symbole(s) dont on a besoin dans un autre fichier, en écrivant un import :

// fichier-b.ts
import { firstName } from './fichier-a';

console.log(firstName);

Voyons maintenant comment les imports/exports sont utilisés dans l’application que nous avons créée avec le CLI.

Syntaxe d’un export

N’importe quel symbole nommé peut être exporté de son fichier (aka “module”), en précédant sa déclaration du mot-clé export.

export const API_KEY = '-wy1LkhpeRz5TqEfI';           // Variable exportée
export class AppComponent { }                         // Classe exportée
export function isAdmin(user: User): boolean { ... }  // Fonction exportée

Dans la pratique, je vous conseille de mettre un export devant toutes les classes que vous créez dans un projet Angular, car il y a peu de chances qu’une classe ne soit utilisée que dans son fichier de déclaration. C’est d’ailleurs ce que fait le CLI quand vous créez une classe de composant avec ng generate component, une classe de service avec ng generate service

Les exports dans notre application

Toutes les classes de l’appli qu’on a générée avec le CLI sont précédées du mot-clé export :

// app.module.ts
export class AppModule { }

// app.component.ts
export class AppComponent { }

On peut d’ailleurs exporter n’importe quel symbole nommé, pas uniquement des classes :

export const API_KEY = '-wy1LkhpeRz5TqEfI';           // Variable exportée
export interface AppSettings { }                      // Interface exportée
export function isAdmin(user: User): boolean { ... }  // Fonction exportée

En règle générale, prenez l’habitude d’exporter tous les symboles de votre code de manière à pouvoir les utiliser partout dans votre application en les important.

Vous pouvez omettre le mot-clé export si vous êtes certain de ne pas avoir besoin du symbole en dehors de son fichier de déclaration.

Syntaxe d’un import

Un import permet d’utiliser localement un symbole qui est déclaré dans un autre fichier ET précédé du mot-clé export. La syntaxe générale repose sur le mot-clé import. N’oubliez pas les accolades autour du ou des élément(s) importé(s).

import { symbole } from './chemin/du/module';

On peut importer plusieurs symboles du même module en les séparant par des virgules :

import { Component, Input, Output } from '@angular/core';

Il ne faut PAS mettre l’extension du fichier depuis lequel on importe :

// CORRECT, alors que le fichier est app.module.ts
import { AppModule } from './app/app.module';

// INCORRECT
import { AppModule } from './app/app.module.ts';

Imports relatifs

Les imports relatifs sont résolus par rapport à l’emplacement du fichier courant. Le chemin d’un import relatif commence TOUJOURS par au moins un point “.”.

Dans une application Angular, les imports depuis vos propres fichiers de code sont toujours relatifs.

import { AppModule } from './app/app.module';
import { User } from '../auth';

Imports non-relatifs

Les imports non-relatifs sont résolus par rapport au répertoire node_modules du projet. Le chemin d’un import non relatif ne commence JAMAIS par un point “.”.

Dans une application Angular, les imports depuis le framework Angular ou depuis des librairies tierce-partie (installées avec npm) sont toujours non relatifs.

// Import depuis Angular
import { Component, Input } from '@angular/core';

// Import depuis la librairie ng-bootstrap
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

NB. Ne pas confondre module JavaScript et module Angular

Pour terminer, ne confondez pas module JavaScript, ce dont on vient de parler, et module Angular.

Un module JavaScript est un fichier dont le scope est privé.

Un module Angular est une classe décorée avec @NgModule.

Comme le code d’un module Angular est placé dans un module/fichier et qu’on utilise deux fois le terme “module”, c’est un peu troublant…

Les imports dans notre application

À chaque fois qu’on veut utiliser une classe, une variable, une fonction, etc. qui vient d’un autre fichier, il suffit de l’importer au début de son code.

Prenons par exemple le fichier app.module.ts de notre application. Tous les symboles qui sont utilisés dans le code sont importés dans les premières lignes :

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

...

On a deux symboles importés du framework Angular, BrowserModule et NgModule. Il s’agit d’imports non-relatifs, car leurs chemins ne commencent pas par un point “.”. Ces imports sont résolus par rapport au répertoire node_modules du projet (soit par exemple, PROJET/node_modules/@angular/platform-browser/).

On a ensuite AppComponent qui est importé du fichier app.component.ts. Cet import est dit relatif, car son chemin commence par un point “.” et il est résolu par rapport à l’emplacement du fichier courant. Comme app.module.ts et app.component.ts sont dans le même répertoire, le chemin d’import est simplement './app.component'.

La syntaxe générale d’un import est donc la suivante :

import { symbole1, symbole2, ... } from './chemin/du/fichier';

Retenez :

  • Qu’un symbole doit être exporté pour pouvoir être importé (!)
  • Qu’on peut importer plusieurs symboles du même fichier en les séparant par des virgules.
  • Qu’on utilise des chemins relatifs quand on importe depuis notre propre code, et non-relatifs quand on importe depuis Angular ou d’autres librairies situées dans node_modules.
  • Qu’il faut omettre l’extension du fichier duquel on importe. Par exemple, on écrit import ... from './app.component' pour importer du fichier app.component.ts.