Typescript es6导入模块"文件不是模块错误"

Baz*_*nga 101 javascript typescript ecmascript-6

我正在使用带有es6模块语法的typescript 1.6.

我的文件是:

test.ts:

module App {
  export class SomeClass {
    getName(): string {
      return 'name';
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

main.ts:

import App from './test';

var a = new App.SomeClass();
Run Code Online (Sandbox Code Playgroud)

当我尝试编译该main.ts文件时,我收到此错误:

错误TS2306:文件'test.ts'不是模块.

我怎么能做到这一点?

Rad*_*ler 117

扩展 - 根据一些评论提供更多详细信息

错误

错误TS2306:文件'test.ts'不是模块.

来自这里描述的事实http://exploringjs.com/es6/ch_modules.html

17.模块

本章介绍了内置模块在ECMAScript 6中的工作原理.

17.1概述

在ECMAScript 6中,模块存储在文件中.每个文件只有一个模块,每个模块只有一个文件.您有两种从模块导出内容的方法.这两种方式可以混合使用,但通常最好单独使用它们.

17.1.1多个命名导出

可以有多个命名导出:

//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}
...
Run Code Online (Sandbox Code Playgroud)

17.1.2单一默认导出

可以有一个默认导出.例如,一个函数:

//------ myFunc.js ------
export default function () { ··· } // no semicolon!
Run Code Online (Sandbox Code Playgroud)

基于上面我们需要export,作为test.js文件的一部分.让我们像这样调整它的内容:

// test.js - exporting es6
export module App {
  export class SomeClass {
    getName(): string {
      return 'name';
    }
  }
  export class OtherClass {
    getName(): string {
      return 'name';
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以用这些方式导入它:

import * as app1 from "./test";
import app2 = require("./test");
import {App} from "./test";
Run Code Online (Sandbox Code Playgroud)

我们可以使用这样的导入内容:

var a1: app1.App.SomeClass  = new app1.App.SomeClass();
var a2: app1.App.OtherClass = new app1.App.OtherClass();

var b1: app2.App.SomeClass  = new app2.App.SomeClass();
var b2: app2.App.OtherClass = new app2.App.OtherClass();

var c1: App.SomeClass  = new App.SomeClass();
var c2: App.OtherClass = new App.OtherClass();
Run Code Online (Sandbox Code Playgroud)

并调用方法来查看它的运行情况:

console.log(a1.getName())
console.log(a2.getName())
console.log(b1.getName())
console.log(b2.getName())
console.log(c1.getName())
console.log(c2.getName())
Run Code Online (Sandbox Code Playgroud)

原始部分试图帮助减少命名空间使用的复杂程度

原始部分:

我强烈建议查看此问答:

如何在TypeScript外部模块中使用名称空间?

让我引用第一句话:

不要在外部模块中使用"名称空间".

不要这样做.

认真.停止.

...

在这种情况下,我们只是不需要module内部test.ts.这可能是调整后的内容test.ts:

export class SomeClass
{
    getName(): string
    {
        return 'name';
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里阅读更多

出口=

在前面的示例中,当我们使用每个验证器时,每个模块仅导出一个值.在这种情况下,当单个标识符同样如此时,通过它们的限定名称使用这些符号是很麻烦的.

export =语法指定该从模块中导出的单个对象.这可以是类,接口,模块,函数或枚举.导入时,导出的符号将直接使用,并且不受任何名称限定.

我们可以稍后使用它:

import App = require('./test');

var sc: App.SomeClass = new App.SomeClass();

sc.getName();
Run Code Online (Sandbox Code Playgroud)

在这里阅读更多:

可选模块加载和其他高级加载方案

在某些情况下,您可能只想在某些条件下加载模块.在TypeScript中,我们可以使用下面显示的模式来实现此模式和其他高级加载方案,以直接调用模块加载器而不会丢失类型安全性.

编译器检测是否在发出的JavaScript中使用了每个模块.对于仅用作类型系统一部分的模块,不会发出require调用.对未使用的引用进行剔除是一种很好的性能优化,并且还允许可选地加载这些模块.

模式的核心思想是import id = require('...')语句使我们能够访问外部模块公开的类型.模块加载器是动态调用的(通过require),如下面的if块所示.这利用了参考剔除优化,因此仅在需要时加载模块.为了使这个模式起作用,重要的是通过导入定义的符号仅用于类型位置(即从不在将被发送到JavaScript中的位置).


A. *_*Tim 11

以上答案是正确的.但以防万一...在VS Code中出现相同的错误.不得不重新保存/重新编译抛出错误的文件.

  • 这对我有用。我只是删除了一个分号,重新添加它并再次保存文件,然后运行 ​​Webpack 就可以了。活着的好时光。 (5认同)
  • 我习惯了 Webstorm,并没有意识到 VS Code 中不会自动保存文件。这个答案让我减轻了很多痛苦,谢谢。 (2认同)

Zen*_*tzi 11

除了A. Tim 的回答之外,有时即使这样也不起作用,所以你需要:

  1. 使用智能感知重写导入字符串。有时这可以解决问题
  2. 重新启动 VS 代码


Sha*_*tin 9

我怎么能做到这一点?

您的示例声明了一个TypeScript <1.5 内部模块,现在称为命名空间.旧module App {}语法现在相当于namespace App {}.因此,以下工作:

// test.ts
export namespace App {
    export class SomeClass {
        getName(): string {
            return 'name';
        }
    }
}

// main.ts
import { App } from './test';
var a = new App.SomeClass();
Run Code Online (Sandbox Code Playgroud)

话虽如此...

尽量避免导出名称空间,而是导出模块(以前称为外部模块).如果需要,您可以使用命名空间导入模式在导入时使用命名空间,如下所示:

// test.ts
export class SomeClass {
    getName(): string {
        return 'name';
    }
}

// main.ts
import * as App from './test'; // namespace import pattern
var a = new App.SomeClass();
Run Code Online (Sandbox Code Playgroud)

  • 这仍然是一个好的做法吗?根据这个答案(/sf/answers/2499439001/),尝试导入这样的函数或类然后调用它 - “根据 ES6 规范是非法的”。 (2认同)