Что означает "... разрешает немодульный объект и не может быть импортировано с использованием этой конструкции" означает?

У меня есть несколько файлов 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()

Невозможно вызвать выражение, тип которого не имеет сигнатуры вызова.

Что дает?

Ответ 1

Почему это не работает

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! Ламе! Но горе - нормальная часть программирования. Переходите к пятой стадии в модели Kübler-Ross: Принятие.

TypeScript здесь говорится, что это не работает, потому что оно не работает. Существуют хаки (добавление объявления namespace в MyClass - это популярный способ притворяться, что это работает), и они могут работать сегодня в вашем конкретном пакете модулей downleveling (например, rollup), но это иллюзорно. В дикой природе еще не реализовано никаких реализаций модулей ES6, но это не будет верно навсегда.

Представьте свое будущее, пытаясь запустить нестандартную реализацию модуля ES6 и обнаружив, что вы настроили себя на серьезный сбой, пытаясь использовать синтаксис ES6, чтобы сделать то, что ES6 явно не делает.

Я хочу использовать мой нестандартный загрузчик модулей

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

Измените MyConsumer.ts на:

import A from './a';

И укажите параметр командной строки allowSyntheticDefaultImports или tsconfig.json.

Обратите внимание, что allowSyntheticDefaultImports не изменяет поведение вашего кода во время выполнения. Это просто флаг, который сообщает TypeScript, что ваш загрузчик модулей создает default экспорт, когда он не существует. Это не будет волшебным образом сделать ваш код работать в nodejs, когда он этого не делал раньше.

Ответ 2

Добавление моих 2 цента здесь означает, что у кого-то еще есть эта проблема.

Мой способ обойти проблему без изменения tsconfig.json (что может быть проблематично в некоторых проектах), я просто отключил правило для oneline.

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