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);
})();
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.