Candy Cup Analogy
Version 1: une tasse pour chaque bonbon
Disons que vous avez écrit du code comme celui-ci:
Mod1.ts
export namespace A {
export class Twix { ... }
}
Mod2.ts
export namespace A {
export class PeanutButterCup { ... }
}
Mod3.ts
export namespace A {
export class KitKat { ... }
}
Vous avez créé cette configuration:
Chaque module (feuille de papier) a son propre gobelet nommé A
. Cela ne sert à rien - vous n'organisez pas réellement vos bonbons ici, vous ajoutez simplement une étape supplémentaire (en le sortant de la tasse) entre vous et les friandises.
Version 2: une tasse à l'échelle mondiale
Si vous n'utilisiez pas de modules, vous pourriez écrire du code comme celui-ci (notez le manque de export
déclarations):
global1.ts
namespace A {
export class Twix { ... }
}
global2.ts
namespace A {
export class PeanutButterCup { ... }
}
global3.ts
namespace A {
export class KitKat { ... }
}
Ce code crée un espace A
de noms fusionné dans la portée globale:
Cette configuration est utile, mais ne s'applique pas dans le cas des modules (car les modules ne polluent pas la portée globale).
Version 3: aller sans coupe
Pour en revenir à l'exemple d' origine, les tasses A
, A
et A
ne sont pas vous faire des faveurs. Au lieu de cela, vous pouvez écrire le code comme suit:
Mod1.ts
export class Twix { ... }
Mod2.ts
export class PeanutButterCup { ... }
Mod3.ts
export class KitKat { ... }
pour créer une image qui ressemble à ceci:
Bien mieux!
Maintenant, si vous pensez toujours à combien vous voulez vraiment utiliser l'espace de noms avec vos modules, lisez la suite ...
Ce ne sont pas les concepts que vous recherchez
Nous devons revenir aux origines de la raison pour laquelle les espaces de noms existent en premier lieu et examiner si ces raisons ont un sens pour les modules externes.
Organisation : les espaces de noms sont pratiques pour regrouper des objets et des types liés de manière logique. Par exemple, en C #, vous allez trouver tous les types de collection dans System.Collections
. En organisant nos types en espaces de noms hiérarchiques, nous offrons une bonne expérience de «découverte» aux utilisateurs de ces types.
Conflits de noms: les espaces de noms sont importants pour éviter les collisions de noms. Par exemple, vous pouvez avoir My.Application.Customer.AddForm
et My.Application.Order.AddForm
- deux types avec le même nom, mais un espace de noms différent. Dans un langage où tous les identificateurs existent dans la même portée racine et tous les assemblys chargent tous les types, il est essentiel que tout soit dans un espace de noms.
Ces raisons ont-elles un sens dans les modules externes?
Organisation : les modules externes sont déjà présents dans un système de fichiers, nécessairement. Nous devons les résoudre par chemin et nom de fichier, il y a donc un schéma d'organisation logique à utiliser. Nous pouvons avoir un /collections/generic/
dossier contenant un list
module.
Conflits de noms : cela ne s'applique pas du tout dans les modules externes. Dans un module, il n'y a aucune raison plausible d'avoir deux objets avec le même nom. Du côté de la consommation, le consommateur d'un module donné peut choisir le nom qu'il utilisera pour se référer au module, de sorte que les conflits de nommage accidentels sont impossibles.
Même si vous ne pensez pas que ces raisons sont correctement traitées par le fonctionnement des modules, la «solution» consistant à essayer d'utiliser des espaces de noms dans des modules externes ne fonctionne même pas.
Boîtes en Boîtes en Boîtes
Une histoire:
Votre ami Bob vous appelle. "J'ai un nouveau plan d'organisation formidable dans ma maison", dit-il, "venez le vérifier!". Bien, allons voir ce que Bob a imaginé.
Vous commencez dans la cuisine et ouvrez le garde-manger. Il y a 60 boîtes différentes, chacune intitulée "Garde-manger". Vous choisissez une boîte au hasard et l'ouvrez. A l'intérieur se trouve une seule boîte intitulée "Grains". Vous ouvrez la boîte "Grains" et trouvez une seule boîte intitulée "Pâtes". Vous ouvrez la boîte "Pâtes" et trouvez une seule boîte intitulée "Penne". Vous ouvrez cette boîte et trouvez, comme vous vous en doutez, un sachet de pâtes penne.
Légèrement confus, vous prenez une boîte adjacente, également étiquetée "Garde-manger". A l'intérieur se trouve une seule boîte, à nouveau étiquetée "Grains". Vous ouvrez la boîte "Grains" et, encore une fois, vous trouvez une seule boîte intitulée "Pâtes". Vous ouvrez la boîte "Pasta" et trouvez une seule boîte, celle-ci est étiquetée "Rigatoni". Vous ouvrez cette boîte et trouvez ... un sac de pâtes rigatoni.
"C'est bien!" dit Bob. "Tout est dans un espace de noms!".
"Mais Bob ..." répondez-vous. "Votre schéma d'organisation est inutile. Vous devez ouvrir un tas de boîtes pour accéder à quoi que ce soit, et il n'est pas plus pratique de trouver quoi que ce soit que si vous veniez de tout mettre dans une seule boîte au lieu de trois . En fait, depuis votre le garde-manger est déjà trié étagère par étagère, vous n'avez pas du tout besoin des boîtes. Pourquoi ne pas simplement mettre les pâtes sur l'étagère et les ramasser quand vous en avez besoin? "
"Vous ne comprenez pas - je dois m'assurer que personne d'autre ne place quelque chose qui n'appartient pas à l'espace de noms" Pantry ". Et j'ai organisé toutes mes pâtes en toute sécurité dans l' Pantry.Grains.Pasta
espace de noms afin que je puisse facilement le trouver"
Bob est un homme très confus.
Les modules sont leur propre boîte
Vous avez probablement eu quelque chose de similaire dans la vie réelle: vous commandez quelques choses sur Amazon, et chaque article apparaît dans sa propre boîte, avec une petite boîte à l'intérieur, avec votre article emballé dans son propre emballage. Même si les boîtes intérieures sont similaires, les envois ne sont pas utilement «combinés».
Pour l'analogie avec la boîte, l'observation clé est que les modules externes sont leur propre boîte . Ce pourrait être un élément très complexe avec beaucoup de fonctionnalités, mais tout module externe donné est sa propre boîte.
Guide pour les modules externes
Maintenant que nous avons compris que nous n'avons pas besoin d'utiliser des «espaces de noms», comment devrions-nous organiser nos modules? Voici quelques principes directeurs et exemples.
Exportez le plus près possible du niveau supérieur
- Si vous n'exportez qu'une seule classe ou fonction, utilisez
export default
:
MyClass.ts
export default class SomeType {
constructor() { ... }
}
MyFunc.ts
function getThing() { return 'thing'; }
export default getThing;
Consommation
import t from './MyClass';
import f from './MyFunc';
var x = new t();
console.log(f());
Ceci est optimal pour les consommateurs. Ils peuvent nommer votre type comme ils le souhaitent ( t
dans ce cas) et n'ont pas à faire de pointage étranger pour trouver vos objets.
- Si vous exportez plusieurs objets, placez-les tous au niveau supérieur:
MyThings.ts
export class SomeType { ... }
export function someFunc() { ... }
Consommation
import * as m from './MyThings';
var x = new m.SomeType();
var y = m.someFunc();
- Si vous exportez un grand nombre de choses, alors seulement devez-vous utiliser le mot
module
- namespace
clé / :
MyLargeModule.ts
export namespace Animals {
export class Dog { ... }
export class Cat { ... }
}
export namespace Plants {
export class Tree { ... }
}
Consommation
import { Animals, Plants} from './MyLargeModule';
var x = new Animals.Dog();
Drapeaux rouges
Tous les éléments suivants sont des drapeaux rouges pour la structuration des modules. Vérifiez que vous n'essayez pas de nommer vos modules externes si l'un de ces éléments s'applique à vos fichiers:
- Un fichier dont la seule déclaration de niveau supérieur est
export module Foo { ... }
(supprimer Foo
et déplacer tout «vers le haut» d'un niveau)
- Un fichier qui a un seul
export class
ou export function
qui n'est pasexport default
- Plusieurs fichiers qui ont le même
export module Foo {
niveau supérieur (ne pensez pas qu'ils vont se combiner en un seul Foo
!)
Rien de mal à la réponse de Ryan, mais pour les personnes qui sont venus ici à la recherche de la façon de maintenir une structure d' une classe par fichier tout en utilisant correctement les espaces de noms ES6, veuillez vous référer à cette ressource utile de Microsoft.
Une chose qui n'est pas claire pour moi après avoir lu le document est: comment importer le module entier (fusionné) avec un seul
import
.Modifiez Encercler pour mettre à jour cette réponse. Quelques approches de l'espace de noms émergent dans TS.
Toutes les classes de modules dans un seul fichier.
Importez des fichiers dans l'espace de noms et réaffectez
Barils
Une dernière considération. Vous pouvez nommer chaque fichier
Mais comme on importe deux classes du même espace de noms, TS se plaindra qu'il y a un identifiant en double. La seule solution, cette fois, consiste à alias l'espace de noms.
Cet aliasing est absolument odieux, alors ne le faites pas. Vous êtes mieux avec une approche ci-dessus. Personnellement, je préfère le «baril».
la source
const fs = require('fs')
,fs
est l'espace de noms.import * as moment from 'moment'
,moment
est l'espace de noms. C'est l'ontologie, pas la spécification.require
exemple ne s'applique pas à eux pour un certain nombre de raisons, y compris le fait que les espaces de noms ES6 peuvent ne pas être appelés, alors qu'ilrequire
renvoie un objet simple qui peut très bien être appelable.Essayez d'organiser par dossier:
baseTypes.ts
dog.ts
tree.ts
LivingThings.ts
main.ts
L'idée est que votre module lui-même ne devrait pas se soucier / savoir qu'il participe à un espace de noms, mais cela expose votre API au consommateur d'une manière compacte et sensible qui est indépendante du type de système de modules que vous utilisez pour le projet.
la source
tree.ts
que ce soit à partir du moment où il n'a aucun membre exporté?import
etrequire
ensemble dans une seule déclaration.Petit appauvrissement d'Albinofrenchy réponse:
base.ts
dog.ts
things.ts
main.ts
la source
OP, je suis avec toi mec. encore une fois, il n'y a rien de mal à cette réponse avec plus de 300 votes positifs, mais mon avis est:
qu'est-ce qui ne va pas avec le fait de mettre les classes dans leurs propres fichiers chaleureux et individuels? Je veux dire que cela rendra les choses beaucoup mieux, non? (ou quelqu'un comme un fichier de 1000 lignes pour tous les modèles)
alors alors, si le premier est réalisé, il faut importer importer importer ... importer juste dans chacun des fichiers modèle comme man, srsly, un fichier modèle, un fichier .d.ts, pourquoi il y en a tellement * s là-dedans? ça devrait être simple, bien rangé, et c'est tout. Pourquoi ai-je besoin d'importations là-bas? Pourquoi? C # a des espaces de noms pour une raison.
Et d'ici là, vous utilisez littéralement "filenames.ts" comme identificateurs. Comme identifiants ... Venez sur son 2017 maintenant et nous le faisons toujours? Ima retourne sur Mars et dort encore 1000 ans.
Donc, malheureusement, ma réponse est: non, vous ne pouvez pas rendre la chose "namespace" fonctionnelle si vous n'utilisez pas toutes ces importations ou en utilisant ces noms de fichiers comme identifiants (ce qui, je pense, est vraiment idiot). Une autre option est: mettez toutes ces dépendances dans une boîte appelée filenameasidentifier.ts et utilisez
enveloppez-les pour qu'ils n'essaient pas d'accéder à d'autres classes du même nom lorsqu'ils essaient simplement d'obtenir une référence de la classe juste au-dessus d'eux.
la source
Plusieurs des questions / commentaires que j'ai vus autour de ce sujet me semblent comme si la personne utilisait
Namespace
où ils voulaient dire «alias de module». Comme Ryan Cavanaugh l'a mentionné dans l'un de ses commentaires, vous pouvez avoir un module «Wrapper» réexportant plusieurs modules.Si vous voulez vraiment tout importer du même nom / alias de module, combinez un module wrapper avec un mappage de chemins dans votre
tsconfig.json
.Exemple:
./path/to/CompanyName.Products/Foo.ts
./path/to/CompanyName.Products/Bar.ts
./path/to/CompanyName.Products/index.ts
tsconfig.json
main.ts
Remarque : La résolution du module dans les fichiers de sortie .js devra être gérée d'une manière ou d'une autre, comme avec ce https://github.com/tleunen/babel-plugin-module-resolver
Exemple
.babelrc
pour gérer la résolution d'alias:la source
Essayez ce module d'espaces de noms
namespaceModuleFile.ts
bookTreeCombine.ts
--- partie de compilation ---
la source
dog.ts
tree.ts
la source
La bonne façon d'organiser votre code consiste à utiliser des répertoires distincts à la place des espaces de noms. Chaque classe sera dans son propre fichier, dans son dossier d'espace de noms respectif. index.ts ne réexportera que chaque fichier; aucun code réel ne doit se trouver dans le fichier index.ts. Organiser votre code comme celui-ci facilite la navigation et est auto-documenté en fonction de la structure du répertoire.
Vous l'utiliseriez alors comme tel:
la source