为什么导入节点模块会破坏atom-typescript中的内部Typescript命名空间?

时间:2015-09-11 20:10:46

标签: typescript

我有一个非常小的节点Typescript项目,具有以下结构:

App structure

尝试在index.ts文件中导入“diff”模块时,如下所示:

import * as diff from 'diff';

Atom-typescript突然失去了找到我的“fgtApp.Interfaces”命名空间的能力:

Loses autocomplete of internal namespace

一旦我删除了import语句,node就能解析“fgtApp.Interfaces”命名空间,不会出现这样的问题:

Autocomplete working properly without import declaration

这是atom-typescript中的错误还是我对导入这些外部模块的方式有所了解的错误?

1 个答案:

答案 0 :(得分:6)

这并非特别是atom-typescript的问题。 atom-typescript插件使用官方的TypeScript语言服务(与Visual Studio相同),因此这在任何编辑器中都会出现问题。

问题在于,一旦指定了导入或导出,该文件就会变成一个模块("外部模块" pre-TypeScript 1.5)。这意味着当import * as diff from 'diff';存在时,index.ts中声明的内容仅变为本地内容,并且不会考虑/合并到全局名称空间中。

  

TypeScript规范,第11.1节: ...包含至少一个外部导入声明,导出分配或顶级导出声明的源文件被视为单独的外部模块。在外部模块中声明的实体仅在该模块的范围内,但可以使用导入声明将导出的实体导入到其他模块中

当您不使用外部模块时,TypeScript允许不同文件中的命名空间相互构建。一旦开始使用外部模块,不再使用变通方法就不会出现这种情况。在这种情况下,通常最好切换到使用外部模块 - 如果您正在制作Node项目,这一点非常简单,因为您不必担心捆绑。

而不是"深命名空间" (例如fgtApp.category.thing)就像C#和.NET一样鼓励 - 开始考虑将每个TypeScript源文件作为自己的模块。如果您确实需要层次结构,请实现具有文件夹结构的层次结构。

即使noImplicitAny处于活动状态,此代码也可以正常工作:

<强> interfaces.d.ts

// Notice that this is a d.ts file.  Since it will only contain interfaces,
//  making it a d.ts file means TypeScript doesn't have to worry about
//  emitting it and you also can't accidentally put executable code here.
export interface IFgtService {
    authenticateDisable: boolean;
    failedAttempt: boolean;
    authenticate: (username: string, password: string) => boolean;
}

export interface IAnotherInterfaceAsAnExample {
    isCool: boolean;
}

<强> service.ts

// since there is no "relative path", diff will come from node_modules.
import * as diff from 'diff';
// since there IS a relative path, interfaces will come from ./interfaces.d.ts
import * as interfaces from './interfaces';

// You can still use namespaces inside an "external module", but mainly they
//  serve as a convenient way to bundle stuff for a one-line export (see
//  the last line of this file).
namespace Service {
  export class FgtService implements interfaces.IFgtService {
    authenticateDisable = true;
    failedAttempt = true;
    authenticate = (username: string, password: string) => {
      let d = diff.d;
      return true;
    }
  }
}
export = Service;

<强> index.ts

import {FgtService} from './Service';

const myService = new FgtService();
console.log(myService.authenticateDisable);