【问题标题】:Typescript: Visibility within the same Namespace across multiple files打字稿:跨多个文件的同一命名空间内的可见性
【发布时间】:2018-09-20 16:53:12
【问题描述】:

您能帮帮我吗?这是一个错误还是我误解了文档?

我在一个命名空间中有两个文件 - 你会在下面找到一个更简单的版本。

Typescript 文档state that “即使文件是分开的,它们也可以贡献给同一个命名空间,并且可以像定义在一个文件中一样被使用”。 因此,我假设一个文件中的一个类可以访问同一命名空间中的另一个文件,即使它没有被导出。 (因为如果它们被定义在同一个地方就会出现这种情况)

但是,tsc 抱怨它找不到名称“Dispatcher”。为什么会这样?我此时是否误解了文档?或者它只是一个编译器错误?如果是前者,那就太可惜了,因为只有命名空间的可见性对单元测试和封装有很大帮助。

代码:

(为简单起见更改了代码。如果存在语法错误,则由该错误引起):

Application.ts:

/// <reference path="Dispatcher.ts"/>
namespace Application {
    export class Application {
        constructor() {
            new Dispatcher(); 
        }
    }
}

Dispatcher.ts:

namespace Application {
    class Dispatcher { /* ... */ }
}

【问题讨论】:

  • 不,必须导出成员才能跨不同文件“贡献”到命名空间。如果您查看生成的 JavaScript 代码,您会明白为什么会这样,所有值都在 IIFE 中声明,因此未导出的值仅在该特定函数的上下文中可见。此外,如果没有这种行为,您将无法在有助于该命名空间的 any 文件中拥有两个具有相同名称的私有属性,这是不可取的。

标签: typescript namespaces


【解决方案1】:

Typescript 文档指出“即使文件是分开的, 它们每个都可以贡献给同一个命名空间,并且可以作为 如果它们都被定义在一个中”。

这取决于“贡献到同一个命名空间”的精确定义。当前的解释是“任何导出的内容都可以在任何地方使用,任何未导出的内容仅在定义它的命名空间部分内可用”。 language specification中是这样解释的:

命名空间提供了一种组织代码和声明的机制 命名容器的层次结构。命名空间已命名成员 每个都表示一个值、一个类型或一个命名空间,或某种组合 其中,这些成员可能是本地的或出口的。一个人的身体 命名空间对应于执行一次的函数,因此 提供一种机制来保证本地状态 隔离。命名空间可以被认为是 立即调用函数表达式 (IIFE) 模式。

如果同一个命名空间有多个声明,每个都编译成单独的IIFE,如Dispatcher.ts的编译javascript代码所示:

var Application;
(function (Application) {
    class Dispatcher {
    }
})(Application || (Application = {}));

结果是Dispatcher 被限定在函数内部,并且无法从外部访问。

即使您在同一个文件中重复了两次 namespace Application,每个都将定义自己的 Dispatcher 副本 - 此代码没有错误:

namespace Application {
    class Dispatcher { /* ... */ }
}

namespace Application {
    class Dispatcher { /* ... */ }
}

使Dispatcher 可以从外部namespace { ... } 访问的唯一方法是导出它。通过导出,Dispatcher 成为Application 对象的属性:

namespace Application {
    export class Dispatcher { /* ... */ }
}

编译代码:

var Application;
(function (Application) {
    class Dispatcher {
    }
    Application.Dispatcher = Dispatcher;
})(Application || (Application = {}));

这种行为在实现方面是有意义的。实现命名空间,以便在所有命名空间实例之间共享未导出的对象,但不能从外部访问,这确实很麻烦。

【讨论】:

  • 非常感谢您的快速回答。还有一个问题:如果我理解正确,我不会在任何地方声明模块——只有命名空间和 reference 指令。是否发生了对模块的隐式转换?
  • 哇!非常感谢,这是一个很棒的答案! :) 真的是我想知道的!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-09
  • 2018-09-23
  • 1970-01-01
  • 1970-01-01
  • 2012-04-28
  • 1970-01-01
相关资源
最近更新 更多