如何在TypeScript外部模块中使用名称空间? [英] How do I use namespaces with TypeScript external modules?

查看:162
本文介绍了如何在TypeScript外部模块中使用名称空间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些代码:

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 {

  }
}

这一切都让人非常困惑。我想让一堆外部模块为同一命名空间提供类型, Living.Things 。似乎这根本不起作用 - 我在 dogs.ts 中看不到 Animal 。我必须在 tree.ts 中写下完整的命名空间名称 b.Living.Things.Plant 。它不适用于跨文件在同一命名空间中组合多个对象。我该怎么做?

This is all very confusing. I want to have a bunch of external modules all contribute types to the same namespace, Living.Things. It seems that this doesn't work at all -- I can't see Animal in dogs.ts. I have to write the full namespace name b.Living.Things.Plant in tree.ts. It doesn't work to combine multiple objects in the same namespace across file. How do I do this?

推荐答案

糖果杯类比



版本1:每个糖果的杯子



假设你写了这样的代码:

Candy Cup Analogy

Version 1: A cup for every candy

Let's say you wrote some code like this:

Mod1 .ts

export namespace A {
    export class Twix { ... }
}

Mod2.ts

export namespace A {
    export class PeanutButterCup { ... }
}

Mod3.ts

export namespace A {
     export class KitKat { ... }
}

你'我创建了这个设置:

You've created this setup:

每个模块(纸张)都有自己的杯子命名为 A 。这没用 - 你实际上并没有在这里组织你的糖果,你只是在你和你的点心之间增加了一个额外的步骤(从杯子里取出)。

Each module (sheet of paper) gets its own cup named A. This is useless - you're not actually organizing your candy here, you're just adding an additional step (taking it out of the cup) between you and the treats.

如果您不使用模块,你可以编写这样的代码(注意缺少 export 声明):

If you weren't using modules, you might write code like this (note the lack of export declarations):

global1.ts

namespace A {
    export class Twix { ... }
}

global2.ts

namespace A {
    export class PeanutButterCup { ... }
}

global3.ts

namespace A {
     export class KitKat { ... }
}

代码在全局范围内创建合并的命名空间 A

This code creates a merged namespace A in the global scope:

此设置很有用,但不适用于模块(因为模块不会污染全局范围)。

This setup is useful, but doesn't apply in the case of modules (because modules don't pollute the global scope).

回到原始示例,杯子 A A ,而 A 对你没有好处。相反,您可以将代码编写为:

Going back to the original example, the cups A, A, and A aren't doing you any favors. Instead, you could write the code as:

Mod1.ts

export class Twix { ... }

Mod2。 ts

export class PeanutButterCup { ... }

Mod3.ts

export class KitKat { ... }

创建如下图片:

好多了!

现在,如果你还在考虑你真的想在模块中使用名称空间,请继续阅读...

Now, if you're still thinking about how much you really want to use namespace with your modules, read on...

我们需要回到起初为什么名称空间存在的起源和检查这些原因是否有意义或外部模块。

We need to go back to the origins of why namespaces exist in the first place and examine whether those reasons make sense for external modules.

组织:命名空间可以方便地将逻辑相关的对象和类型组合在一起。例如,在C#中,您将在 System.Collections 中找到所有集合类型。通过将我们的类型组织到分层命名空间中,我们为这些类型的用户提供了良好的发现体验。

Organization: Namespaces are handy for grouping together logically-related objects and types. For example, in C#, you're going to find all the collection types in System.Collections. By organizing our types into hierarchical namespaces, we provide a good "discovery" experience for users of those types.

名称冲突:命名空间很重要避免命名冲突。例如,您可能有 My.Application.Customer.AddForm My.Application.Order.AddForm - 两个具有相同名称但具有不同名称空间的类型。在所有标识符都存在于同一根范围内并且所有程序集都加载所有类型的语言中,将所有内容都放在命名空间中至关重要。

Name Conflicts: Namespaces are important to avoid naming collisions. For example, you might have My.Application.Customer.AddForm and My.Application.Order.AddForm -- two types with the same name, but a different namespace. In a language where all identifiers exist in the same root scope and all assemblies load all types, it's critical to have everything be in a namespace.

这些理由是否有意义外部模块?

Do those reasons make sense in external modules?

组织:外部模块必然存在于文件系统中。我们必须通过路径和文件名来解决它们,因此我们有一个逻辑组织方案供我们使用。我们可以在 / collections / generic / 文件夹中包含列表模块。

Organization: External modules are already present in a file system, necessarily. We have to resolve them by path and filename, so there's a logical organization scheme for us to use. We can have a /collections/generic/ folder with a list module in it.

名称冲突:这在外部模块中根本不适用。 模块中,没有合理的理由让两个具有相同名称的对象。从消费方面来看,任何给定模块的使用者都会选择他们用来引用模块的名称,因此不可能发生意外命名冲突。

Name Conflicts: This doesn't apply at all in external modules. Within a module, there's no plausible reason to have two objects with the same name. From the consumption side, the consumer of any given module gets to pick the name that they will use to refer to the module, so accidental naming conflicts are impossible.

即使您不相信模块的工作原理能够充分解决这些原因,尝试在外部模块中使用命名空间的解决方案也不会工作。

Even if you don't believe that those reasons are adequately addressed by how modules work, the "solution" of trying to use namespaces in external modules doesn't even work.

故事:


你的朋友Bob给你打电话。 我家里有一个很棒的新组织计划,他说,来看看吧!。干得好,让我们看看Bob提出了什么。

Your friend Bob calls you up. "I have a great new organization scheme in my house", he says, "come check it out!". Neat, let's go see what Bob has come up with.

你从厨房开始打开食品室。有60个不同的盒子,每个盒子都标有Pantry。你随机挑选一个盒子然后打开它。里面是一个标有谷物的盒子。打开谷物框,找到一个标有Pasta的方框。打开Pasta框,找到一个标有Penne的方框。你打开这个盒子,就像你期望的那样找到一袋通心粉。

You start in the kitchen and open up the pantry. There are 60 different boxes, each labelled "Pantry". You pick a box at random and open it. Inside is a single box labelled "Grains". You open up the "Grains" box and find a single box labelled "Pasta". You open the "Pasta" box and find a single box labelled "Penne". You open this box and find, as you expect, a bag of penne pasta.

稍微混淆,你拿起一个相邻的盒子,也标有Pantry。里面是一个盒子,再次标记为谷物。打开谷物框,再次找到一个标有Pasta的方框。你打开Pasta框并找到一个盒子,这个盒子标有Rigatoni。你打开这个盒子,找到......一袋通心粉意大利面。

Slightly confused, you pick up an adjacent box, also labelled "Pantry". Inside is a single box, again labelled "Grains". You open up the "Grains" box and, again, find a single box labelled "Pasta". You open the "Pasta" box and find a single box, this one is labelled "Rigatoni". You open this box and find... a bag of rigatoni pasta.

太棒了!鲍勃说。 一切都在命名空间!。

"It's great!" says Bob. "Everything is in a namespace!".

但是鲍勃......你回答。 你的组织方案是无用的。你必须打开一堆盒子才能找到任何东西,找到任何东西实际上并不比你把所有东西都放在一个盒子里而不是。事实上,由于您的食品储藏室已经逐个分类,您根本不需要这些食品盒。为什么不在货架上放置意大利面并在需要时将其拿起来它?

"But Bob..." you reply. "Your organization scheme is useless. You have to open up a bunch of boxes to get to anything, and it's not actually any more convenient to find anything than if you had just put everything in one box instead of three. In fact, since your pantry is already sorted shelf-by-shelf, you don't need the boxes at all. Why not just set the pasta on the shelf and pick it up when you need it?"

你不明白 - 我需要确保没有其他人放置不属于'Pantry'命名空间的东西。我已经安全地将所有面食组织到 Pantry.Grains.Pasta 命名空间中,这样我就可以轻松找到它

"You don't understand -- I need to make sure that no one else puts something that doesn't belong in the 'Pantry' namespace. And I've safely organized all my pasta into the Pantry.Grains.Pasta namespace so I can easily find it"

Bob是一个非常困惑的人。

Bob is a very confused man.



模块是他们自己的盒子



你可能在现实生活中发生了类似的事情:你在亚马逊上订购了一些东西,每件物品都出现在自己的盒子里,里面有一个小盒子,你的物品被包裹着自己的包装。即使内部盒子类似,出货也没有用组合。

Modules are Their Own Box

You've probably had something similar happen in real life: You order a few things on Amazon, and each item shows up in its own box, with a smaller box inside, with your item wrapped in its own packaging. Even if the interior boxes are similar, the shipments are not usefully "combined".

按照盒子类比,关键观察是外部模块是他们的自己的盒子。它可能是一个非常复杂的项目,具有很多功能,但任何给定的外部模块都是它自己的盒子。

Going with the box analogy, the key observation is that external modules are their own box. It might be a very complex item with lots of functionality, but any given external module is its own box.

现在我们已经发现我们不需要使用'命名空间',我们应该如何组织模块?一些指导原则和示例如下。

Now that we've figured out that we don't need to use 'namespaces', how should we organize our modules? Some guiding principles and examples follow.


  • 如果您只导出单个类或函数,请使用 export default

  • If you're only exporting a single class or function, use export default:

MyClass.ts

export default class SomeType {
  constructor() { ... }
}

MyFunc.ts

function getThing() { return 'thing'; }
export default getThing;

消费

import t from './MyClass';
import f from './MyFunc';
var x = new t();
console.log(f());

这对消费者来说是最佳选择。他们可以随意命名你的类型(在这种情况下 t )并且不必做任何无关的点击来找到你的对象。

This is optimal for consumers. They can name your type whatever they want (t in this case) and don't have to do any extraneous dotting to find your objects.


  • 如果您要导出多个对象,请将它们全部放在顶层:

MyThings.ts

export class SomeType { ... }
export function someFunc() { ... }

消费

import * as m from './MyThings';
var x = new m.SomeType();
var y = m.someFunc();




  • 如果你要出口大量的东西,那么只有这样才能你使用模块 / 命名空间关键字:

    • If you're exporting a large number of things, only then should you use the module/namespace keyword:
    • MyLargeModule.ts

      export namespace Animals {
        export class Dog { ... }
        export class Cat { ... }
      }
      export namespace Plants {
        export class Tree { ... }
      }
      

      消费

      import { Animals, Plants} from './MyLargeModule';
      var x = new Animals.Dog();
      






      红旗



      以下所有都是模块结构的红色标志。仔细检查您是否尝试命名外部模块,如果其中任何一个适用于您的文件:


      Red Flags

      All of the following are red flags for module structuring. Double-check that you're not trying to namespace your external modules if any of these apply to your files:


      • 一个只有顶级的文件-level声明是导出模块Foo {...} (删除 Foo 并将所有内容'向上移动'一个级别)

      • 具有单个导出类导出函数的文件't 导出默认值

      • 具有相同导出模块的多个文件Foo {在顶层(不要认为这些将合并为一个 Foo !)

      • A file whose only top-level declaration is export module Foo { ... } (remove Foo and move everything 'up' a level)
      • A file that has a single export class or export function that isn't export default
      • Multiple files that have the same export module Foo { at top-level (don't think that these are going to combine into one Foo!)

      这篇关于如何在TypeScript外部模块中使用名称空间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆