【问题标题】:TypeScript ES6 import module "File is not a module error"Typescript es6导入模块“文件不是模块错误”
【发布时间】:2015-12-24 15:59:19
【问题描述】:

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

我的文件是:

test.ts:

module App {
  export class SomeClass {
    getName(): string {
      return 'name';
    }
  }
}

ma​​in.ts:

import App from './test';

var a = new App.SomeClass();

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

错误 TS2306:文件“test.ts”不是模块。

我怎样才能做到这一点?

【问题讨论】:

  • 我遇到了这个问题,我在类中没有构造函数,添加了一个,问题就消失了
  • 我只是导入了错误的文件...

标签: javascript typescript ecmascript-6


【解决方案1】:

扩展 - 提供基于某些 cmets 的更多细节

错误

错误 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));
}
...

17.1.2 单一默认导出

可以有一个默认导出。比如一个函数:

//------ myFunc.js ------
export default function () { ··· } // no semicolon!

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

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

现在我们可以通过以下三种方式导入它:

import * as app1 from "./test";
import app2 = require("./test");
import {App} from "./test";

我们可以像这样消费进口的东西:

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();

并调用该方法以查看它的实际效果:

console.log(a1.getName())
console.log(a2.getName())
console.log(b1.getName())
console.log(b2.getName())
console.log(c1.getName())
console.log(c2.getName())

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

原创部分:

我强烈建议您查看此问答:

How do I use namespaces with TypeScript external modules?

让我引用第一句话:

不要在外部模块中使用“命名空间”。

不要这样做。

说真的。停止。

...

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

export class SomeClass
{
    getName(): string
    {
        return 'name';
    }
}

在这里阅读更多

Export =

在前面的例子中,当我们消费每个验证器时,每个模块只导出一个值。在这种情况下,通过它们的限定名称来处理这些符号很麻烦,而单个标识符也可以。

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

我们以后可以这样消费它:

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

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

sc.getName();

在这里阅读更多:

Optional Module Loading and Other Advanced Loading Scenarios

在某些情况下,您可能只想在某些条件下加载一个模块。在 TypeScript 中,我们可以使用如下所示的模式来实现这个和其他高级加载场景,以直接调用模块加载器而不会失去类型安全。

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

该模式的核心思想是 import id = require('...') 语句让我们可以访问外部模块公开的类型。模块加载器是动态调用的(通过 require),如下面的 if 块所示。这利用了引用剔除优化,以便仅在需要时加载模块。要使这种模式起作用,重要的是通过 import 定义的符号仅用于类型位置(即永远不会出现在将被发送到 JavaScript 中的位置)。

【讨论】:

  • 但是这个:import App = require('./test');不是 es6 模块的语法。这是常见的js。我可以使用 es6 模块语法吗?
  • @JsIsAwesome 您正在尝试将 JS 模块与 Typescript 模块混合使用。您需要使用其中一种,而不是两者的混合。
  • 这个答案没有引用 ES6 语法
  • @phiresky,你是什么意思?
  • 示例使用import x = require('test'),而ES6模块语法类似于import x from "test"
【解决方案2】:

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

【讨论】:

  • 这对我有用。我只是删除了一个分号,重新添加它并再次保存文件,然后运行 ​​Webpack 就可以了。活着的好时光。
  • 我习惯了 Webstorm 并没有意识到文件不会自动保存在 VS Code 中。这个答案为我省去了很多痛苦,谢谢。
  • VS Code 中有一个自动保存的设置。我不使用它,因为 VS Code 已经备份了未保存的文件,而且我并不总是使用 git。
  • 太棒了!我关闭文件并再次打开它,问题解决了,我猜它与打开时更改文件名有关。
【解决方案3】:

我怎样才能做到这一点?

您的示例声明了一个 TypeScript 内部模块,现在称为namespace。旧的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();

话虽这么说......

Try to avoid exporting namespaces 改为导出模块(以前称为外部模块)。如果需要,您可以在导入时使用带有 namespace import pattern 的命名空间,如下所示:

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

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

【讨论】:

  • 这仍然是一个好习惯吗?根据这个答案 (stackoverflow.com/a/35706271/2021224),尝试导入这样的函数或类然后调用它 - “根据 ES6 规范是非法的”。
【解决方案4】:

除了A. Tim's answer 之外,有时即使这样也不起作用,所以您需要:

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

【讨论】:

  • stackblitz 相同 - 重新编译的文件导入模块并且一切正常,干杯
  • 我的代码格式不正确时也遇到过这种情况。当我将我的类拆分为他们自己的文件时,VSCode 缩进了我的复制+粘贴类代码,并且 VSCode 缩进了 export class... { 之后的所有内容,这是 Angular 不喜欢的,这给了我这个问题。修复格式后,编译没有问题。
【解决方案5】:

除了蒂姆的回答之外,当我拆分重构文件时,我也遇到了这个问题,将其拆分为自己的文件。

由于某种原因,VSCode 缩进了我的 [class] 代码的一部分,这导致了这个问题。起初这很难注意到,但在我意识到代码缩进后,我将代码格式化,问题就消失了。

例如,类定义第一行之后的所有内容在粘贴过程中都会自动缩进。

export class MyClass extends Something<string> {
    public blah: string = null;

    constructor() { ... }
  }

【讨论】:

    【解决方案6】:

    我遇到了这个问题,我忘记了导出类。

    【讨论】:

      【解决方案7】:

      以防万一这对你有用,因为它对我有用,我有这些文件

      //server.ts
      
      class Server{
      ...
      }
      
      exports.Server = Server
      
      //app.ts
      
      import {Server} from './server.ts'
      

      这实际上引发了一个错误,但我将server.ts 更改为

      //server.ts
      
      export class Server{
      ...
      }
      
      

      它成功了??

      注意:我正在使用这个配置

       "target": "esnext",
       "module": "commonjs",
      

      【讨论】:

      • 谢谢,但不适用于 svelte,因为它有自己的内置功能声明
      【解决方案8】:

      该文件需要从核心添加组件,因此将以下导入添加到顶部

      从'@angular/core'导入{组件};

      【讨论】:

        猜你喜欢
        • 2015-08-13
        • 1970-01-01
        • 1970-01-01
        • 2017-01-04
        • 2019-05-25
        • 2015-07-19
        • 2018-03-08
        • 1970-01-01
        • 2019-01-04
        相关资源
        最近更新 更多