声明模块与声明名称空间类型脚本

Ank*_*oni 8 typescript typescript1.5

我对打字稿内部模块declare module和之间的区别感到困惑declare namespace

我不清楚的另一点是:为内部模块打字稿具有复杂的名称空间是个好主意。

例如

declare module com.xyz.company.test.mynamespace {
    interface Iabc {
        // stuff  
    }

    interface Ixys{ 
       //stuff 
    }

    // or

    export interface Ipqr { 
        // stuff 
    }
}
Run Code Online (Sandbox Code Playgroud)

mic*_*ico 7

我找到了有关命名空间和模块的 [1] 手册。首先,关于术语的澄清:

关于术语的说明:请务必注意,在 TypeScript 1.5 中,术语已更改。“内部模块”现在是“命名空间”。“外部模块”现在只是“模块”,-

因此,来自同一本书的不同章节 [2] 示例:

模块

  interface StringValidator {
      isAcceptable(s: string): boolean;
  }
  ..
   // Validators to use
  let validators: { [s: string]: StringValidator; } = {};
Run Code Online (Sandbox Code Playgroud)

命名空间

  namespace Validation {
      export interface StringValidator {
          isAcceptable(s: string): boolean;
      }
   ...
    // Validators to use
    let validators: { [s: string]: Validation.StringValidator; } = {};
Run Code Online (Sandbox Code Playgroud)

来源 [3] 讲述了它们的用法:

不在外部模块中的命名空间可以跨越文件,所以如果你在同一个命名空间中,你可以引用命名空间导出的任何东西,而无需任何类型的导入。

在这种情况下,您可能可以使用命名空间,但在 [4] 中提到了这个比较:

模块:

   //typescript
   export class Validaton { 
       ... 
   }

   //becomes, in javascript:
   export class Validation {
       ... 
   }
Run Code Online (Sandbox Code Playgroud)

命名空间:

   // typescript:
   namespace Validation {
       const foo = 123;
   }

  //This becomes, in es6:
  (function(Validation) {
         Validation.foo = 123;
   })(Validation || (Validation = {}))
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,第二个在 JavaScript ES6 中变得非常不自然,因此 [3] 上的另一个答案甚至声明名称空间已过时。


关于第二个问题:

Source [1] 讲述了一个案例,过度使用命名空间使代码看起来有点无用的复杂:

   import * as shapes from "./shapes";
   let t = new shapes.Shapes.Triangle(); // shapes.Shapes?
Run Code Online (Sandbox Code Playgroud)

所以,这让我想到:应该避免所有对代码命名空间级别无用或意义不大的东西。作者甚至说:

TypeScript 中模块的一个关键特性是两个不同的模块永远不会为同一个范围提供名称。由于模块的使用者决定为其分配什么名称,因此无需主动将导出的符号包装在命名空间中。


来源:

[1] https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html

[2] https://www.typescriptlang.org/docs/handbook/namespaces.html#validators-in-a-single-file

[3]模块 vs 命名空间 - 导入 vs 需要打字稿

[4] https://michelenasti.com/2019/01/23/is-typescript-namespace-feature-deprecated.html


Edw*_*win 6

declare关键字用于在打字稿中创建环境声明,为编译器提供有关每个模块的类型信息。

在 ES6 之前,JavaScript 没有module. 您创建的每个变量都将在全局范围内结束。例如。如果您有以下 2 个文件:

// a.js
var name = 'a';
Run Code Online (Sandbox Code Playgroud)
// b.js
var name = 'b';
Run Code Online (Sandbox Code Playgroud)

name将是一个全局变量,因此如果 b.js 在 a.js 之后加载,name则值为'b';

引入模块模式是为了防止这些变量冲突:

// a.js
(function() {
    var name = 'a';
})();
Run Code Online (Sandbox Code Playgroud)
// b.js
(function() {
    var name = 'b';
})();
Run Code Online (Sandbox Code Playgroud)

现在每个文件name在函数范围内都有自己的变量。不能在函数外访问它们。

当你想导出变量时,你可以通过传入一个全局变量来实现:

var module = {}; // this is global

// a.js
(function(mod) {
    var name = 'a';
    mod.a = name;
})(module); // <-- passing the module variable into the function scope of a.js

// b.js
(function(mod) {
    var name = 'b';
    mod.b = name;
})(module);
Run Code Online (Sandbox Code Playgroud)

现在值已导出到module.amodule.b。在 ES6 之前,这是许多 JS 库用来创建模块的机制。Typescript 称这种机制internal modulesnamespaces.

命名空间只是在全局命名空间中命名的 JavaScript 对象

这些全局模块变量的环境类型声明可以使用declare namespace语法定义。



自 ES6 引入以来,模块已成为语言本身的一个特性,可以使用导入和导出语法创建。因此,这些模块的类型声明将使用declare module语法。

从 ECMAScript 2015 开始,模块是语言的本机部分,所有兼容的引擎实现都应该支持。因此,对于新项目模块将是推荐的代码组织机制

https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html


至于你的第二个问题,在可能的情况下,降低模块对象的嵌套级别通常是一个更好的设计。