Що означає «… розв’язується до немодульної сутності і не може бути імпортована за допомогою цієї конструкції»?


93

У мене є кілька файлів TypeScript:

MyClass.ts

class MyClass {
  constructor() {
  }
}
export = MyClass;

MyFunc.ts

function fn() { return 0; }
export = fn;

MyConsumer.ts

import * as MC from './MyClass';
import * as fn from './MyFunc';
fn();

Це дає мені помилки при спробі використання new

Модуль "MyClass" розв'язується з немодульним об'єктом і не може бути імпортований за допомогою цієї конструкції.

і при спробі дзвонити fn()

Неможливо викликати вираз, типу якого відсутній підпис дзвінка.

Що дає?


2
Дякуємо, що поділилися відповіддю. Я б запропонував видалити javascriptяк основний тег і залишити ecmascript-6, тому що тут є основний тег typescript. Питання помилково передбачає, що export =(функція TS) може бути парною import ... from, тоді як вона повинна бути спареноюimport = . Це в основному імпорт / експорт модуля ES6 проти CJS / AMD.
колба Естуса

Відповіді:


156

Чому це не працює

import * as MC from './MyClass';

Це importсинтаксис у стилі ES6 / ES2015 . Точне значення цього полягає в "Візьміть завантажений з нього об'єкт простору імен модуля ./MyClassта використовуйте його локально як MC". Зокрема, " об'єкт простору імен модулів " складається лише з простого об'єкта з властивостями. Об'єкт модуля ES6 не можна викликати як функцію або за допомогою new.

Щоб сказати це ще раз: Об'єкт простору імен модуля ES6 не можна викликати як функцію або з new.

Те, що ви importвикористовуєте * as Xз модуля, має лише властивості. У перетвореному CommonJS це може бути не дотримано повністю, але TypeScript повідомляє вам, що таке поведінка, визначена стандартом.

Що працює?

Вам потрібно буде використовувати синтаксис імпорту стилю CommonJS, щоб використовувати цей модуль:

import MC = require('./MyClass');

Якщо ви керуєте обома модулями, ви можете використовувати export defaultзамість цього:

MyClass.ts

export default class MyClass {
  constructor() {
  }
}

MyConsumer.ts

import MC from './MyClass';

Мені сумно з цього приводу; Правила німі.

Було б непогано використовувати синтаксис імпорту ES6, але тепер я повинен це зробити import MC = require('./MyClass'); ? Це так 2013 рік! Кульга! Але горе - це нормальна частина програмування. Будь ласка, перейдіть до п’ятої сцени в моделі Кюблера-Росса: Прийняття.

Тут TypeScript повідомляє, що це не працює, бо не працює. Є хаки (додавання namespaceдекларації до MyClassпопулярного способу зробити вигляд, що це працює), і вони можуть працювати сьогодні у вашому конкретному пакетному модулі нижчого рівня (наприклад, зведений), але це ілюзорно. Ще не існує жодної реалізації модуля ES6, але це не буде вірно.

Зобразіть своє майбутнє «я», намагаючись запустити реалізацію простого нативного модуля ES6 і виявивши, що ви налаштували себе на великий збій, намагаючись використовувати синтаксис ES6, щоб зробити те, що ES6 явно не робить .

Я хочу скористатися своїм нестандартним навантажувачем модулів

Можливо, у вас є завантажувач модулів, який "корисно" створює defaultекспорт, коли такого не існує. Я маю на увазі, люди створюють стандарти з причини, але ігнорування стандартів іноді - це цікаво, і ми можемо подумати, що це круто.

Змініть MyConsumer.ts на:

import A from './a';

І вкажіть allowSyntheticDefaultImportsкомандний рядок абоtsconfig.json параметр.

Зверніть увагу, що allowSyntheticDefaultImportsповедінка коду не змінюється взагалі. Це лише прапор, який повідомляє TypeScript, що завантажувач модулів створює defaultекспорт, коли його немає. Це не буде магічно змусити ваш код працювати в nodejs, коли цього не було раніше.


Чи не вимагає стиль commonjs цілі commonjs? Чи є спосіб зробити цю роботу, коли ви орієнтуєтесь на es6 / es2015?
Стів Бузонас

Ви не можете змусити його націлюватись на ES6, оскільки він не працює в ES6 ...
Ryan

Чи правильно я розумію, що якщо я націлююсь на модулі ES2015, немає ніякого способу посилання на модуль CommonJS, який є export = MyClass? Мій єдиний варіант - встановити для свого модуля commonjsта продовжувати погіршувати світ, не використовуючи сучасні ES?
Міхей Золту

6
У примітках до випуску 2.7 , нижче --esModuleInterop, сказано: "Ми настійно рекомендуємо застосовувати його як до нових, так і до існуючих проектів". На мою думку, цю відповідь (і запитання / політику щодо часто заданих питань у DefinitelyTypedцих посиланнях тут) слід змінити, щоб відобразити нову позицію.
Алек Мев

1
Так дуже зухвало.
jmealy

25

TypeScript 2.7 представляє підтримку, видаючи нові допоміжні методи: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#support-for-import-d-from-cjs-form- commonjs-модулі-з --- esmoduleinterop

Тож у tsconfig.json додайте ці два налаштування:

{
    // Enable support for importing CommonJS modules targeting es6 modules
    "esModuleInterop": true,

    // When using above interop will get missing default export error from type check since
    // modules use "export =" instead of "export default", enable this to ignore errors.
    "allowSyntheticDefaultImports": true
}

А тепер ви можете використовувати:

import MyClass from './MyClass';

Замість використання esModuleInteropя використав resolveJsonModuleпоряд з вашими іншими пропозиціями використання, allowSyntheticDefaultImportsі це працювало на мене.
Едгар Кінтеро

6

Якщо додати мої 2 копійки тут, якщо у когось іншого є ця проблема.

Мій спосіб вирішити проблему без зміни tsconfig.json(що може бути проблематично в деяких проектах), я просто вимкнув правило для однієї лінії.

import MC = require('./MyClass'); // tslint:disable-line


5

Я отримав цю помилку при спробі включити пакет пакету дебюту npm у свій проект.

Коли я спробував прийняте рішення вище, я отримав виняток:

Призначення імпорту не можна використовувати при націлюванні на модулі ECMAScript. Розглянемо використання 'import * як ns з "mod"', 'import {a} з "mod"', 'import d з "mod" або іншого формату модуля.

Це закінчилось:

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