Модуль імпорту машинопису es6 "Файл - це помилка модуля"


127

Я використовую typecript 1.6 з синтаксисом модулів es6.

Мої файли:

test.ts:

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

main.ts:

import App from './test';

var a = new App.SomeClass();

Коли я намагаюся скласти main.tsфайл, я отримую цю помилку:

Помилка TS2306: Файл 'test.ts' не є модулем.

Як я можу це досягти?


У мене виникло це питання, у мене не було конструктора в класі, додали один і проблема пішла
dorriz

Відповіді:


139

Розширений - для отримання детальної інформації на основі деяких коментарів

Помилка

Помилка 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())

Оригінальна частина намагається допомогти зменшити складність у використанні простору імен

Оригінальна частина:

Я дуже рекомендую перевірити це питання:

Як використовувати простори імен із зовнішніми модулями TypeScript?

Дозвольте навести перше речення:

Не використовуйте "простори імен" у зовнішніх модулях.

Не робіть цього.

Серйозно. Стій.

...

У цьому випадку нам просто не потрібно moduleвсередині test.ts. Це може бути змінено його зміст test.ts:

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

Детальніше читайте тут

Експорт =

У попередньому прикладі, коли ми споживали кожен валідатор, кожен модуль експортував лише одне значення. У таких випадках, як працювати з цими символами, можна отримати їх кваліфіковане ім'я, коли один ідентифікатор зробив би так само добре.

export =Синтаксис визначає один об'єкт , який експортується з модуля . Це може бути клас, інтерфейс, модуль, функція або перерахунок. При імпорті експортований символ використовується безпосередньо та не кваліфікується жодним іменем.

пізніше ми можемо споживати його так:

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

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

sc.getName();

Детальніше читайте тут:

Додатковий сценарій завантаження модуля та інші розширені сценарії завантаження

У деяких випадках ви можете завантажити модуль лише за певних умов. У TypeScript ми можемо використовувати схему, показану нижче, для реалізації цього та інших розширених сценаріїв завантаження, щоб безпосередньо викликати завантажувачі модулів, не втрачаючи безпеку типу.

Компілятор визначає, чи використовується кожен модуль у випромінюваному JavaScript. Для модулів, які використовуються лише як частина системи типів, не вимагається викликів. Цей вибір невикористаних посилань є хорошою оптимізацією продуктивності, а також дозволяє додатково завантажувати ці модулі.

Основна ідея шаблону полягає в тому, що оператор import id = requ ('...') надає нам доступ до типів, відкритих зовнішнім модулем. Завантажувач модулів викликається (через потребу) динамічно, як показано на блоках if нижче. Це використовує оптимізацію опорного кулірування, щоб модуль завантажувався лише за потреби. Щоб ця схема працювала, важливо, щоб символ, визначений за допомогою імпорту, використовувався лише в позиціях типу (тобто ніколи в позиції, яка випромінюється в JavaScript).


1
Але це: імпортувати додаток = вимагати ('./ тест'); не є синтаксисом модулів es6. це звичайний js. Чи можу я це зробити з синтаксисом модулів es6?
Базінга

@JsIsAwesome Ви намагаєтесь змішати JS модулі з Typescript модулями. Потрібно використовувати те чи інше, а не суміш обох.
JJJ

Ця відповідь не стосується синтаксису
ES6

@phiresky, що ти маєш на увазі?
Радім Келер

1
Спасибі, це чудово.
phiresky

24

Вище відповіді правильні. Але про всяк випадок ... З'явилася така ж помилка у коді VS. Довелося повторно зберегти / перекомпілювати файл, який видав помилку.


3
Це працювало для мене. Я просто вилучив напівколонку, повторно додав її і знову зберег файл, а потім запустив Webpack. Чудовий час бути живим.
Рей Хоган

1
Я звик до Webstorm і не зрозумів, що файли не зберігаються автоматично у коді VS. Ця відповідь врятувала мені великий біль, дякую.
cib

У коді VS є налаштування для автоматичного збереження. Я не використовую його, оскільки VS Code вже створює резервну копію збережених файлів, і я не завжди використовую git.
амарки

13

Як я можу це досягти?

Ваш приклад оголошує внутрішній модуль 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();

Це сумно...

Постарайтеся уникати експорту просторів імен і замість цього експортуйте модулі (які раніше називали зовнішніми модулями ). Якщо потрібно, ви можете скористатися простором імен при імпорті з такою схемою імпорту простору імен :

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

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

1
Це все-таки хороша практика? Відповідно до цієї відповіді ( stackoverflow.com/a/35706271/2021224 ), спроба імпортувати функцію або клас на кшталт цього, а потім викликати її - "згідно з специфікацією ES6 незаконно".
Андрій Прохоров

2

Окрім відповіді А. Тіма, є випадки, коли навіть це не працює, тому вам потрібно:

  1. Перезапишіть рядок імпорту, використовуючи intellisense. Іноді це вирішує проблему
  2. Перезапустіть код VS

1
те саме для stackblitz - перекомпільований файл, який імпортує модуль, і все працює чудово, ура
godblessstrawberry

Я також зазнав цього, коли мій код не був відформатований правильно. VSCode відрізав мій код класу копія + вставка, коли я розділяв свої класи на власні файли, а VSCode розрізував усе після того export class... {, що кутовий не сподобався, що дало мені цю проблему. Після виправлення форматування, складено без проблем.
Парк Гая

0

Окрім відповіді Тіма, ця проблема сталася для мене, коли я розбивав файл рефакторингу, розділяючи його на власні файли.

VSCode чомусь відрізав частини мого [класу] коду, що спричинило цю проблему. Спочатку це було важко помітити, але після того, як я зрозумів, що код позначений відступом, я відформатував код і проблема зникла.

наприклад, усе після першого рядка визначення класу було автоматично відведено під час вставки.

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

    constructor() { ... }
  }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.