web-dev-qa-db-fra.com

Comment utiliser les espaces de noms avec les modules externes TypeScript?

J'ai du code:

baseTypes.ts

export module Living.Things {
  export class Animal {
    move() { /* ... */ }
  }
  export class Plant {
    photosynthesize() { /* ... */ }
  }
}

dog.ts

import b = require('./baseTypes');

export module Living.Things {
  // Error, can't find name 'Animal', ??
  export class Dog extends Animal {
    woof() { }
  }
}

tree.ts

// Error, can't use the same name twice, ??
import b = require('./baseTypes');
import b = require('./dogs');

module Living.Things {
  // Why do I have to write b.Living.Things.Plant instead of b.Plant??
  class Tree extends b.Living.Things.Plant {

  }
}

Tout cela est très déroutant. Je veux avoir un tas de modules externes qui contribuent tous les types au même espace de noms, Living.Things. Il semble que cela ne fonctionne pas du tout - je ne peux pas voir Animal dans dogs.ts. Je dois écrire le nom complet de l'espace de nom b.Living.Things.Plant dans tree.ts. Cela ne fonctionne pas de combiner plusieurs objets dans le même espace de noms d'un fichier à l'autre. Comment puis-je faire cela?

182
Ryan Cavanaugh

La réponse de Ryan n’a rien d’erreur, mais si vous êtes venu ici pour savoir comment conserver une structure une classe par fichier tout en utilisant correctement les espaces de noms ES6, veuillez vous référer à this ressource utile de Microsoft.

Une chose que je ne comprends pas bien après avoir lu la documentation est la suivante: comment importer l'intégralité du module (fusionné) avec un uniqueimport.

Edit Revenez à la position précédente pour mettre à jour cette réponse. Quelques approches du nompacing apparaissent dans TS. 

Toutes les classes de modules dans un seul fichier. 

export namespace Shapes {
    export class Triangle {}
    export class Square {}      
}

Importer des fichiers dans un espace de noms et réaffecter

import { Triangle as _Triangle } from './triangle';
import { Square as _Square } from './square';

export namespace Shapes {
  export const Triangle = _Triangle;
  export const Square = _Square;
}

Tonneaux

// ./shapes/index.ts
export { Triangle } from './triangle';
export { Square } from './square';

// in importing file:
import * as Shapes from './shapes/index.ts';
// by node module convention, you can ignore '/index.ts':
import * as Shapes from './shapes';
let myTriangle = new Shapes.Triangle();

Une dernière considération. Vous pouvez _ espace de noms chaque fichier

// triangle.ts
export namespace Shapes {
    export class Triangle {}
}

// square.ts
export namespace Shapes {
    export class Square {}
}

Mais comme on importe deux classes du même espace de noms, TS se plaindra de la présence d'un identificateur en double. La seule solution car cette fois-ci consiste à aliaser l'espace de noms.

import { Shapes } from './square';
import { Shapes as _Shapes } from './triangle';

// ugh
let myTriangle = new _Shapes.Shapes.Triangle();

Ce pseudonyme est absolument odieux, alors ne le faites pas. Vous êtes mieux avec une approche ci-dessus. Personnellement, je préfère le «tonneau».

46
Jefftopia

Essayez d'organiser par dossier:

baseTypes.ts

export class Animal {
    move() { /* ... */ }
}

export class Plant {
    photosynthesize() { /* ... */ }
}

dog.ts

import b = require('./baseTypes');

export class Dog extends b.Animal {
    woof() { }
}   

tree.ts

import b = require('./baseTypes');

class Tree extends b.Plant {
}

LivingThings.ts

import dog = require('./dog')
import tree = require('./tree')

export = {
    dog: dog,
    tree: tree
}

main.ts

import LivingThings = require('./LivingThings');
console.log(LivingThings.Tree)
console.log(LivingThings.Dog)

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 de manière compacte et raisonnable, indépendamment du type de système de module utilisé pour le projet. 

6
Albinofrenchy

Petite amélioration de Albino Frenchy réponse:

base.ts

export class Animal {
move() { /* ... */ }
}

export class Plant {
  photosynthesize() { /* ... */ }
}

dog.ts

import * as b from './base';

export class Dog extends b.Animal {
   woof() { }
} 

choses.ts

import { Dog } from './dog'

namespace things {
  export const dog = Dog;
}

export = things;

main.ts

import * as things from './things';

console.log(things.dog);
3
Mike Vitik

OP je suis avec vous mec ..__ encore une fois aussi, il n'y a rien de mal à cette réponse avec plus de 300 votes, mais mon opinion est la suivante:

  1. qu'y a-t-il de mal à 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)

  2. alors si le premier objectif est atteint, nous devons importer import import ... import uniquement dans chacun des fichiers de modèle, comme man, srsly, un fichier de modèle, un fichier .d.ts, pourquoi il y a tant de * s dedans? ça devrait juste être simple, bien rangé, et c'est tout. Pourquoi j'ai besoin d'importer là-bas? Pourquoi? C # a des espaces de noms pour une raison.

  3. Et à ce moment-là, vous utilisez littéralement "noms de fichiers.ts" comme identificateurs. En tant qu'identifiants ... En 2017, 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 le "espace de noms" fonctionnel si vous n'utilisez pas toutes ces importations ou ces noms de fichiers comme identificateurs (ce qui, à mon avis, est vraiment idiot). Une autre option est la suivante: placez toutes ces dépendances dans une boîte appelée filenameasidentifier.ts et utilisez 

export namespace(or module) boxInBox {} .

enveloppez-les pour qu'ils n'essayent pas d'accéder à d'autres classes du même nom quand ils essaieront simplement d'obtenir une référence de la classe, assis dessus.

2
NO... Bugs...

Plusieurs des questions/commentaires que j'ai vus sur ce sujet me semblent comme si la personne utilisait Namespace où ils signifient «alias de module». Comme Ryan Cavanaugh l'a mentionné dans l'un de ses commentaires, vous pouvez demander à un module «Wrapper» de réexporter plusieurs modules.

Si vous souhaitez vraiment tout importer à partir 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

export class Foo {
    ...
}


./path/to/CompanyName.Products/Bar.ts

export class Bar {
    ...
}


./path/to/CompanyName.Products/index.ts

export { Foo } from './Foo';
export { Bar } from './Bar';



tsconfig.json

{
    "compilerOptions": {
        ...
        paths: {
            ...
            "CompanyName.Products": ["./path/to/CompanyName.Products/index"],
            ...
        }
        ...
    }
    ...
}



main.ts

import { Foo, Bar } from 'CompanyName.Products'

Note: la résolution du module dans les fichiers .js en sortie devra être gérée d'une manière ou d'une autre, comme avec ceci https://github.com/tleunen/babel-plugin-module-resolver

Exemple .babelrc pour gérer la résolution d'alias:

{
    "plugins": [
        [ "module-resolver", {
            "cwd": "babelrc",
            "alias": {
                "CompanyName.Products": "./path/to/TypeScript/build/output/CompanyName.Products/index.js"
            }
        }],
        ... other plugins ...
    ]
}
2
Ryan Thomas

Essayez ce module d'espaces de noms

namespaceModuleFile.ts

export namespace Bookname{
export class Snows{
    name:any;
    constructor(bookname){
        console.log(bookname);
    }
}
export class Adventure{
    name:any;
    constructor(bookname){
        console.log(bookname);
    }
}
}





export namespace TreeList{
export class MangoTree{
    name:any;
    constructor(treeName){
        console.log(treeName);
    }
}
export class GuvavaTree{
    name:any;
    constructor(treeName){
        console.log(treeName);
    }
}
}

bookTreeCombine.ts

--- partie de compilation ---

import {Bookname , TreeList} from './namespaceModule';
import b = require('./namespaceModule');
let BooknameLists = new Bookname.Adventure('Pirate treasure');
BooknameLists = new Bookname.Snows('ways to write a book'); 
const TreeLis = new TreeList.MangoTree('trees present in nature');
const TreeLists = new TreeList.GuvavaTree('trees are the celebraties');
0
Bal mukund kumar

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'espaces de noms respectif. index.ts ne réexportera que chaque fichier; aucun code réel ne devrait être dans le fichier index.ts. En organisant votre code de cette manière, il est beaucoup plus facile de naviguer et l'auto-documentation est basée sur la structure de répertoires.

// index.ts
import * as greeter from './greeter';
import * as somethingElse from './somethingElse';

export {greeter, somethingElse};

// greeter/index.ts
export * from './greetings.js';
...

// greeter/greetings.ts
export const helloWorld = "Hello World";

Vous l'utiliseriez alors comme tel:

import { greeter } from 'your-package'; //Import it like normal, be it from an NPM module or from a directory.
// You can also use the following syntax, if you prefer:
import * as package from 'your-package';

console.log(greeter.helloWorld);
0
NolePTR

dog.ts

import b = require('./baseTypes');

export module Living.Things {
    // Error, can't find name 'Animal', ??
    // Solved: can find, if properly referenced; exporting modules is useless, anyhow
    export class Dog extends b.Living.Things.Animal {
        public woof(): void {
            return;
        }
    }
}

tree.ts

// Error, can't use the same name twice, ??
// Solved: cannot declare let or const variable twice in same scope either: just use a different name
import b = require('./baseTypes');
import d = require('./dog');

module Living.Things {
    // Why do I have to write b.Living.Things.Plant instead of b.Plant??
    class Tree extends b.Living.Things.Plant {
    }
}
0
Alessandro Lendaro