web-dev-qa-db-fra.com

Que signifie "... résout en une entité non modulaire et ne peut pas être importé avec cette construction"?

J'ai des fichiers 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();

Cela me donne des erreurs lorsque j'essaie d'utiliser new

Le module "MyClass" est résolu en une entité autre que le module et ne peut pas être importé à l'aide de cette construction.

et en essayant d'appeler fn()

Impossible d'appeler une expression dont le type ne contient pas de signature d'appel.

Ce qui donne?

88
Ryan Cavanaugh

Pourquoi ça ne marche pas

import * as MC from './MyClass';

Il s'agit de la syntaxe import de style ES6/ES2015. La signification exacte est "Prenez le module objet d’espace de nommage chargé à partir de ./MyClass et utilisez-le localement comme MC". Notamment, le "module objet d'espace de nom " consiste uniquement en un objet brut avec des propriétés. Un objet de module ES6 ne peut pas être appelé en tant que fonction ou avec new.

Pour le répéter: n objet d’espace de nommage de module ES6 ne peut pas être appelé en tant que fonction ou avec new.

La chose que vous import en utilisant * as X à partir d'un module est définie pour n'avoir que des propriétés. Dans CommonJS, cela pourrait ne pas être entièrement respecté, mais TypeScript vous dit quel est le comportement défini par la norme.

Qu'est-ce qui fonctionne?

Vous devez utiliser la syntaxe d'importation de style CommonJS pour utiliser ce module:

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

Si vous contrôlez les deux modules, vous pouvez utiliser export default à la place:

MyClass.ts

export default class MyClass {
  constructor() {
  }
}

MyConsumer.ts

import MC from './MyClass';

Je suis triste à ce sujet; Les règles sont bêtes.

Il aurait été agréable d'utiliser la syntaxe d'importation ES6, mais maintenant je dois faire ceci import MC = require('./MyClass'); chose? C'est tellement 2013! Boiteux! Mais le chagrin est une partie normale de la programmation. Veuillez passer à la cinquième étape du modèle Kübler-Ross: Acceptance.

TypeScript vous dit ici que cela ne fonctionne pas, car cela ne fonctionne pas. Il y a des hacks (ajouter une déclaration namespace à MyClass est un moyen répandu de prétendre que cela fonctionne), et ils pourraient fonctionner aujourd'hui dans votre module de mise à niveau particulier bundler (par exemple rollup), mais cela est illusoire. Il n'y a pas encore d'implémentation de module ES6 dans la nature, mais cela ne sera pas vrai pour toujours.

Imaginez votre avenir, essayez de vous lancer sur une implémentation de module ESO natif neato et découvrez que vous vous êtes préparé à un échec majeur en essayant d'utiliser la syntaxe de ES6 pour faire quelque chose que ES6 n'a pas explicitement fait. .

Je veux profiter de mon chargeur de modules non standard

Peut-être avez-vous un chargeur de modules qui "utilement" crée default exportations quand il n'en existe pas Je veux dire, les gens font des normes pour une raison, mais les ignorer est parfois amusant et nous pouvons penser que c'est une bonne chose à faire.

Remplacez MyConsumer.ts par:

import A from './a';

Et spécifiez la ligne de commande allowSyntheticDefaultImports ou tsconfig.json.

Notez que allowSyntheticDefaultImports ne modifie pas du tout le comportement d'exécution de votre code. C'est simplement un indicateur qui indique à TypeScript que votre chargeur de module crée default exportations lorsqu'il n'en existe pas. Comme par magie, votre code ne fonctionnera pas dans nodejs.

149
Ryan Cavanaugh

TypeScript 2.7 introduit le support en émettant de nouvelles méthodes d'assistance: https://www.typescriptlang.org/docs/handbook/release-notes/TypeScript-2-7.html#support-for-import-d-from- cjs-form-commonjs-modules-with --- esmoduleinterop

Donc, dans tsconfig.json, ajoutez ces deux paramètres:

{
    // 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
}

Et maintenant, vous pouvez utiliser:

import MyClass from './MyClass';
21
Michael

Ajout de mes 2 cents ici au cas où quelqu'un d'autre aurait ce problème.

Ma façon de contourner le problème sans modifier tsconfig.json (ce qui peut poser problème dans certains projets), j'ai simplement désactivé la règle en ligne.

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

4
Shahar Hadas

J'ai eu cette erreur en essayant d'inclure un paquet npm debounce dans mon projet.

Lorsque j'ai essayé la solution acceptée ci-dessus, j'ai eu une exception:

L'affectation d'importation ne peut pas être utilisée pour cibler les modules ECMAScript. Envisagez d'utiliser "import * as ns de" mod "", "importer {a} de" mod "", "importer d de" mod "" ou un autre format de module.

Cela a fini par fonctionner:

import debounce from 'debounce' 
4
NSjonas