114 votes

Module vs espace de nom - Importer vs Requérir Typescript

J'ai beaucoup de confusion avec module/namespace/export y import, require, reference usage. Comme je viens de Java, quelqu'un peut-il m'expliquer en quelques mots quand utiliser quoi et quelle est la bonne conception ? J'ai l'impression de me tromper lorsque j'écris un exemple de projet.

Voici ce que j'ai compris jusqu'à présent 1. module est pour les paquets externes 2. namespace est pour les paquets internes

  • Je n'ai pas compris comment on les catégorise ?
  • Quand exporter une classe, un espace de nom ou un paquet ?
  • Si nous exportons un paquet ou un espace de nom, toutes les classes qui en font partie sont exportées ou doivent être explicitement exportées.
  • Comment chacun d'entre eux peut-il être importé/exigé ?

Selon le document Si je crée chaque fichier "ts" pour chaque gestionnaire/modèle, Typescript ne recommande pas l'utilisation des "namespaces" ? Utiliser directement les chemins de référence ?

Veuillez m'expliquer en détail car je viens d'un milieu différent et je ne suis pas sûr de l'ES6/ES5, etc.

J'ai vu plusieurs personnes soulever/se confondre avec les mêmes questions. J'espère que quelqu'un pourra expliquer en détail un scénario réel.

0 votes

Il a beaucoup d'attention, ce qui répond à votre question. Je ne sais pas pourquoi il a été mis à l'index.

0 votes

@DanPantry, avant de commencer le bounty, il n'y avait pas une seule réponse :(

0 votes

Mon erreur - je n'ai pas comparé les timestamps.

88voto

kayjtea Points 1266

Je n'ai pas compris comment on les catégorise ?

Les espaces de noms sont utilisés pour organiser/encapsuler votre code. Les modules externes sont utilisés pour organiser/encapsuler votre code ET pour localiser votre code au moment de l'exécution. En pratique, vous avez deux choix au moment de l'exécution : 1) combiner tout le code transpilé dans un seul fichier, ou 2) utiliser des modules externes et avoir plusieurs fichiers et exiger un autre mécanisme pour accéder à ces fichiers.

Quand exporter une classe, un espace de nom ou un paquet ?

Pour rendre un type ou une valeur visible en dehors du fichier dans lequel il se trouve, vous devez l'exporter s'il se trouve dans un espace de nom. Le fait que vous l'exportiez au niveau supérieur ou à l'intérieur d'un espace de noms déterminera s'il se trouve maintenant dans un module externe.

Si nous exportons un paquet ou un espace de nom, toutes les classes qui en font partie sont exportées ou doivent être explicitement exportées.

Les classes d'un espace de nom devront toujours être explicitement exportées pour que la classe soit visible à la compilation en dehors du fichier dans lequel elle est définie.

Comment chacun d'entre eux peut-il être importé/exigé ?

Cela dépend si vous utilisez des modules externes. Un module externe devra toujours être importé pour être "utilisé". Importer un espace de noms qui n'est pas dans un module externe revient en fait à fournir un alias pour l'espace de noms -- vous devez toujours préfixer le type/quoi que ce soit avec l'alias (et c'est pourquoi vous ne voulez généralement pas utiliser d'espaces de noms avec des modules externes ; en faisant cela, vous devez toujours utiliser un préfixe lorsque vous faites référence à quoi que ce soit fourni par le module externe). Les espaces de noms qui ne sont pas dans un module externe peuvent couvrir des fichiers, donc si vous êtes dans le même espace de noms, vous pouvez faire référence à tout ce qui est exporté par l'espace de noms sans avoir besoin d'une sorte d'importation.

Pour bien comprendre ce qui précède, il faut avoir quelques connaissances de base. La chose essentielle à comprendre avec les références/espaces de noms/modules externes est ce que ces constructions font au moment de la compilation et ce qu'elles font au moment de l'exécution.

Les directives de référence sont utilisées au moment de la compilation pour localiser les informations de type. Votre source contient un symbole particulier. Comment le compilateur TypeScript peut-il localiser la définition de ce symbole ? La directive de référence a été largement remplacée par le mécanisme tsconfig.json. En utilisant tsconfig.json, vous indiquez au compilateur où se trouvent toutes vos sources.

Les espaces de noms peuvent contenir des définitions de types et/ou des implémentations. Si un espace de noms ne contient que des informations de type, il n'a aucune manifestation d'exécution. Vous pouvez le vérifier en regardant la sortie JS et en trouvant un fichier JS vide. Si un espace de noms contient du code d'implémentation, alors le code est enveloppé dans une fermeture qui est affectée à une variable globale portant le même nom que l'espace de noms. Avec des espaces de noms imbriqués, il y aura une variable globale pour l'espace de noms racine. Encore une fois, vérifiez la sortie JS. Les espaces de noms sont historiquement la façon dont les bibliothèques JS côté client ont tenté d'éviter le problème des collisions de noms. L'idée est d'envelopper toute votre bibliothèque dans une fermeture et d'exposer ensuite une empreinte globale aussi petite que possible - une seule variable globale référençant la fermeture. Le problème est toujours que vous avez revendiqué un nom dans l'espace global. Et si vous vouliez, disons, deux versions d'une bibliothèque ? Un espace de noms TypeScript pose toujours le problème de la localisation de la source de l'espace de noms. C'est-à-dire que le code source qui fait référence à A.B a toujours le problème d'indiquer au compilateur comment localiser A.B -- soit en utilisant des directives de référence, soit en utilisant tsconfig.json. Ou encore en plaçant l'espace de noms dans un module externe, puis en important ce module externe.

Les modules externes sont issus de JS côté serveur. Il existe une correspondance univoque entre un module externe et un fichier du système de fichiers. Vous pouvez utiliser la structure de répertoire du système de fichiers pour organiser les modules externes dans une structure imbriquée. L'importation d'un module externe introduit généralement toujours une dépendance d'exécution à l'égard de ce module externe (l'exception est lorsque vous importez un module externe mais n'utilisez ensuite aucune de ses exportations en position de valeur - c'est-à-dire que vous importez le module externe uniquement pour obtenir ses informations de type). Un module externe est implicitement dans une fermeture, ce qui est essentiel : l'utilisateur du module peut affecter la fermeture à la variable locale de son choix. TypeScript/ES6 ajoute une syntaxe supplémentaire pour le mappage des exportations des modules externes aux noms locaux, mais il s'agit d'un simple détail. Du côté du serveur, la localisation d'un module externe est relativement simple : il suffit de localiser le fichier représentant le module externe sur le système de fichiers local. Si vous voulez utiliser des modules externes du côté client, dans un navigateur, cela devient plus complexe car il n'y a pas d'équivalent au système de fichiers qui a le module disponible pour le chargement. Il faut donc trouver un moyen de regrouper tous ces fichiers côté client sous une forme qui puisse être utilisée à distance dans le navigateur. C'est là qu'interviennent les regroupeurs de modules comme Webpack (Webpack fait bien plus que regrouper des modules) et Browserify. Les bundlers de modules permettent la résolution à l'exécution de vos modules externes dans le navigateur.

Scénario du monde réel : AngularJS. Faire comme si les modules externes n'existaient pas, utiliser un seul espace de noms pour limiter la pollution de l'espace global (dans l'exemple ci-dessous, une seule variable MyApp est tout ce qui se trouve dans l'espace global), exporter uniquement les interfaces, et utiliser l'injection de dépendances AngularJS pour rendre les implémentations disponibles à l'utilisation. Mettez toutes les classes dans un répertoire Root, ajoutez un tsconfig.json à Root, installez angularjs typings dans le même répertoire Root pour que tsconfig.json le récupère aussi, combinez tous les résultats dans un seul fichier JS. Cela fonctionnera bien pour la plupart des projets si la réutilisation du code n'est pas une préoccupation majeure.

MyService.ts :

namespace MyApp {

    // without an export the interface is not visible outside of MyService.ts
    export interface MyService { 
        ....
    }

    // class is not exported; AngularJS DI will wire up the implementation
    class MyServiceImpl implements MyService {
    }

    angular.module("MyApp").service("myService", MyServiceImpl);
}

MonController.ts :

namespace MyApp {

   class MyController {
       // No import of MyService is needed as we are spanning 
       // one namespace with multiple files.
       // MyService is only used at compile time for type checking. 
       // AngularJS DI is done on the name of the variable. 
       constructor(private myService: MyService) { 
       }
   }
   angular.module("MyApp").controller("myController", MyController);
}

Utilisation de IIFE pour éviter de polluer la portée globale du runtime. Dans cet exemple, aucune variable globale n'est créée. (Un tsconfig.json est supposé).

Foo.ts :

namespace Foo {
    // without an export IFoo is not visible. No JS is generated here
    // as we are only defining a type.
    export interface IFoo {
        x: string;
    }
}

interface ITopLevel {
    z: string;
}

(function(){
    // export required above to make IFoo visible as we are not in the Foo namespace
    class Foo1 implements Foo.IFoo {
        x: string = "abc";
    }
    // do something with Foo1 like register it with a DI system
})();

Bar.ts :

// alias import; no external module created
import IFoo = Foo.IFoo;

(function() {

    // Namespace Foo is always visible as it was defined at
    // top level (outside of any other namespace).
    class Bar1 implements Foo.IFoo {
        x: string;
    }

    // equivalent to above
    class Bar2 implements IFoo {
        x: string;
    }

    // IToplevel is visible here for the same reason namespace Foo is visible
    class MyToplevel implements ITopLevel {
        z: string;
    }

})();

En utilisant IIFE, vous pouvez éliminer l'introduction de MyApp comme variable globale dans le premier exemple.

MyService.ts :

interface MyService { 
    ....
}

(function() {

    class MyServiceImpl implements MyService {
    }

    angular.module("MyApp").service("myService", MyServiceImpl);
})();

MonController.ts :

(function() { 

   class MyController { 
       constructor(private myService: MyService) { 
       }
   }

   angular.module("MyApp").controller("myController", MyController);
})();

30voto

Paleo Points 7884

Il y a deux choses :

  • A module en TypeScript est une notion standard de l'ES6, elle utilise la fonction import / export mots-clés au niveau supérieur du code ;
  • A espace de noms est une notion spécifique à TypeScript pour aider à organiser le code de manière obsolète.

Espaces de noms

C'est une notion presque obsolète. Avant les modules ES6, la façon courante de séparer le code JavaScript dans un navigateur était de créer des variables globales. Par exemple, toutes les fonctions d'une API comme soulignement était situé dans une variable globale nommée _ .

Cette ancienne façon de procéder est comme les paquets Java ou les espaces de noms PHP. Elle n'est pas adaptée au Web. La nouvelle norme ECMAScript résout des problèmes tels que : comment utiliser deux bibliothèques qui ont le même nom ? Comment utiliser deux versions distinctes d'une même bibliothèque ?

Avis : Dans les versions de TypeScript antérieures à la définition ECMAScript des "modules" (été 2014), les espaces de noms étaient appelés "modules internes" et les modules étaient appelés "modules externes".

Avis 2 : Le mot-clé export à l'intérieur d'un namespace est une utilisation non standard du mot-clé en TypeScript. C'est le moyen de déclarer une chose qui est publiquement accessible depuis l'extérieur de l'espace de nom.

Modules ES6

Un module est un fichier qui contient des mots-clés import o export au niveau supérieur du code.

TypeScript suit la norme de l'ECMAScript. Je suggère de lire une bonne introduction aux modules ES6 dans un article de Mozilla.

Si vous voulez utiliser des modules dans une application frontale (dans un navigateur), vous devrez utiliser un bundler ( Webpack [ la documentation ici ], Browserify) ou un chargeur ( SystemJS [ un tutoriel ici ], RequireJS) et de configurer TypeScript avec cet environnement.

Si votre code est exécuté dans Node.js, il suffit de configurer le compilateur TypeScript pour générer le format CommonJS.

Avis : Un espace de nom peut être déclaré dans un module. Dans ce cas, il ne sera pas accessible en tant que variable globale depuis l'extérieur du module. Cependant, il peut être exporté depuis le module.

0 votes

Le compilateur TypeScript ne regroupe-t-il pas automatiquement les modules en un seul fichier .js ?

0 votes

@Kokodoko, Non. Il peut juste concaténer.

0 votes

Erm... quelle est la différence ? .... J'utilise des modules et seulement tsc pour construire un seul fichier .js. Je n'ai pas besoin d'utiliser systemJS, webpack ou browserify.

15voto

basarat Points 22425
  1. module est pour les paquets externes 2. namespace est pour les paquets internes

En fait, le module a été remplacé par le mot-clé namespace mot-clé.

Une meilleure déclaration est donc Modules sont ce que l'on appelait autrefois des modules externes, espace de noms est ce qu'on appelait autrefois les modules internes.

Plus de

J'espère que cela vous aidera davantage : https://basarat.gitbooks.io/typescript/content/docs/project/modules.html

9 votes

Désolé d'informer, les questions sont sans réponse. Je m'attendais à une explication détaillée avec des exemples concrets plutôt qu'une définition tirée d'un manuel.

0 votes

Vous voulez dire qu'il n'y a pas de module clavier en TypeScript maintenant ?

8voto

Nir O. Points 454

" exiger " et " import "Nous pouvons les utiliser de manière interchangeable car nous disposons de transpilateurs qui ne se soucient pas vraiment de savoir si le navigateur les prend en charge de manière native ou non. Mais, alors que " exiger "a ses racines dans un ancien style de codage provenant de CommonJS en 2009, "import" dérive sa syntaxe de la syntaxe ES6 (ES2015) largement acceptée. Vous devez donc utiliser " import " pour les nouveaux projets et non " exiger ".

1 votes

Exactement. C'est si confus, et il y a si peu d'informations à ce sujet, que l'on dit que c'est fondamentalement la même chose. Je me demande pourquoi ça a été voté ?

2voto

Confusion des noms

Aux premiers jours de Typescript, les espaces de noms étaient appelés modules internes et les modules ES6 étaient appelés modules externes .

Maintenant, pour déclarer les espaces de noms, l'équipe de Typescript recommande d'utiliser la balise namespace { } au lieu de la module { } afin d'éviter toute confusion de nom avec les modules externes. En effet, les modules externes sont maintenant simplement des "modules" et les modules internes sont des "espaces de noms".


Espaces de noms

Déclaration

Un espace de noms dans Typescript peut être déclaré à l'aide de l'une ou l'autre des méthodes suivantes namespace ou le module mot-clé. Les deux mots-clés font la même chose. Ensuite, nous pouvons décider quelle partie de notre espace de noms rendre publique en utilisant le mot-clé export mot-clé.

// LivingThings.ts
export namespace Animals {
    export class Dog { }
    export class Cat { }
}
export namespace Plants {
    export class Orchid { }
    export class Bamboo { }
}

// LivingThingsUser.ts
import { Animals, Plants } from "./LivingThings"

Regroupement logique

Avant ES6, les espaces de noms étaient utilisés dans Typescript pour encapsuler les interfaces, les classes, les fonctions et les variables afin de prendre en charge un groupe de fonctionnalités connexes et de masquer les détails de mise en œuvre. De cette façon, nous pouvions empêcher les variables de fuir dans l'espace global. Cela a permis de mieux organiser le code et d'éviter les collisions de noms. Il est désormais recommandé d'utiliser les modules ES6 pour y parvenir.

Les espaces de noms sont maintenant utilisés pour les déclarations d'espaces de noms ambiants.

Utilisation d'un seul fichier

Nous pouvons déclarer des espaces de noms à travers plusieurs fichiers et ils peuvent être concaténés en utilisant --outFile drapeau. Nous pouvons ensuite utiliser ce fichier concaténé dans la fonction <script> dans notre page HTML. Cela nous permet de structurer notre code d'une bonne manière dans une application web côté client avec toutes les dépendances incluses.


Modules

Déclaration

Les modules sont également appelés modules ES6. Nous utilisons plusieurs fichiers pour regrouper les fonctionnalités liées et nous utilisons simplement l'attribut export pour rendre l'objet souhaité publiquement visible.

// Animals.ts
export class Dog { }
export class Cat { }

// Plants.ts
export class Orchid { }
export class Bamboo { }

// LivingThingsUser.ts
import { Dog, Cat } from "./Animals"
import { Orchid, Bamboo } from "./Plants"

Regroupement logique

Le regroupement logique en modules est réalisé en utilisant des fichiers séparés pour regrouper les fonctionnalités liées. Pour cette raison, les modules externes sont également appelés modules de fichiers .

Utilisation d'un seul fichier

Nous ne chargeons pas les modules de l'application web côté client à l'aide de la fonction <script> car les navigateurs peuvent être ralentis par le téléchargement de nombreux fichiers et le rendu de la page en même temps. Pour cela, nous utilisons les chargeurs de modules comme CommonJS, AMD, SystemJS qui nous permettent de charger les fichiers de manière asynchrone ou de concaténer les fichiers de modules externes en un seul fichier optimisé.

Pour le côté serveur, notamment dans Node.js, les modules sont fortement recommandés.

C'est ça !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X