Cosa significa "... si risolve in un'entità non modulo e non può essere importato utilizzando questo costrutto"?


93

Ho alcuni file 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();

Questo mi dà errori quando provo a usare new

Il modulo "MyClass" si risolve in un'entità non modulo e non può essere importato utilizzando questo costrutto.

e quando si cerca di chiamare fn()

Impossibile richiamare un'espressione il cui tipo non dispone di una firma di chiamata.

Cosa succede?


2
Grazie per aver condiviso una risposta. Suggerirei di rimuovere javascriptcome tag principale e di lasciarlo ecmascript-6, perché il tag principale qui è typescript. La domanda presume erroneamente che export =(una funzione TS) possa essere accoppiata import ... from, mentre dovrebbe essere accoppiata conimport = . È fondamentalmente l'importazione / esportazione del modulo ES6 rispetto a CJS / AMD.
Estus Flask

Risposte:


156

Perché non funziona

import * as MC from './MyClass';

Questa è la importsintassi in stile ES6 / ES2015 . Il significato esatto di questo è "Prendi l' oggetto spazio dei nomi del modulo caricato da ./MyClasse usalo localmente come MC". In particolare, l '" oggetto spazio dei nomi del modulo " consiste solo di un oggetto semplice con proprietà. Un oggetto modulo ES6 non può essere richiamato come funzione o con new.

Per dirlo di nuovo: un oggetto spazio dei nomi di un modulo ES6 non può essere richiamato come funzione o con new.

La cosa che importusi * as Xda un modulo è definita per avere solo proprietà. In CommonJS di livello inferiore questo potrebbe non essere pienamente rispettato, ma TypeScript ti dice qual è il comportamento definito dallo standard.

Cosa funziona?

Dovrai utilizzare la sintassi di importazione in stile CommonJS per utilizzare questo modulo:

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

Se controlli entrambi i moduli, puoi utilizzare export defaultinvece:

MyClass.ts

export default class MyClass {
  constructor() {
  }
}

MyConsumer.ts

import MC from './MyClass';

Sono triste per questo; Le regole sono stupide.

Sarebbe stato bello usare la sintassi di importazione di ES6, ma ora devo fare questa import MC = require('./MyClass');cosa? È così 2013! Noioso! Ma il dolore è una parte normale della programmazione. Salta alla fase cinque nel modello Kübler-Ross: Accettazione.

TypeScript qui ti sta dicendo che questo non funziona, perché non funziona. Ci sono hack (l'aggiunta di una namespacedichiarazione a MyClassè un modo popolare per fingere che funzioni ), e potrebbero funzionare oggi nel tuo particolare bundler di moduli di livello inferiore (es. Rollup), ma questo è illusorio. Non ci sono ancora implementazioni di moduli ES6 in circolazione, ma non sarà vero per sempre.

Immagina il tuo sé futuro, provando a eseguire su un'implementazione del modulo ES6 nativo e scoprendo che ti sei preparato per un grave fallimento cercando di utilizzare la sintassi di ES6 per fare qualcosa che ES6 non fa esplicitamente .

Voglio sfruttare il mio caricatore di moduli non standard

Forse hai un caricatore di moduli che "utilmente" crea defaultesportazioni quando non ne esistono. Voglio dire, le persone fanno degli standard per un motivo, ma ignorare gli standard a volte è divertente e possiamo pensare che sia una cosa interessante da fare.

Cambia MyConsumer.ts in:

import A from './a';

E specifica la allowSyntheticDefaultImportsriga di comando o l' tsconfig.jsonopzione.

Nota che allowSyntheticDefaultImportsnon cambia affatto il comportamento di runtime del tuo codice. È solo un flag che dice a TypeScript che il caricatore di moduli crea defaultesportazioni quando non esistono. Magicamente non farà funzionare il tuo codice in nodejs quando non lo faceva prima.


Lo stile commonjs non richiede un target commonjs? Esiste un modo per farlo funzionare quando scegli come target es6 / es2015?
Steve Buzonas

Non puoi farlo funzionare mirando a ES6 perché non funziona in ES6 ...
Ryan Cavanaugh

Ho ragione nel capire che se sto prendendo di mira i moduli ES2015, non c'è modo di fare riferimento a un modulo CommonJS che ha export = MyClass? La mia unica opzione è impostare il mio modulo commonjse continuare a rendere il mondo un posto peggiore non utilizzando il moderno ES?
Micah Zoltu

6
Nelle note di rilascio 2.7 , sotto --esModuleInterop, si dice "Consigliamo vivamente di applicarlo sia a progetti nuovi che esistenti". A mio parere, questa risposta (e la voce / politica delle FAQ in DefinitelyTypedquel link qui) dovrebbe essere modificata per riflettere la nuova posizione.
Alec Mev

1
Quindi così molto sfacciato.
jmealy

25

TypeScript 2.7 introduce il supporto emettendo nuovi metodi di supporto: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#support-for-import-d-from-cjs-form- commonjs-modules-con --- esmoduleinterop

Quindi in tsconfig.json aggiungi queste due impostazioni:

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

E ora puoi usare:

import MyClass from './MyClass';

Invece di usare esModuleInteropho usato resolveJsonModuleinsieme al tuo altro suggerimento di usare allowSyntheticDefaultImportse ha funzionato per me.
Edgar Quintero,

6

Aggiungendo i miei 2 centesimi qui in caso qualcun altro abbia questo problema.

Il mio modo di aggirare il problema senza modificare tsconfig.json(che può essere problematico in alcuni progetti), sono andato semplicemente disabilitando la regola per oneline.

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


5

Ho ricevuto questo errore durante il tentativo di includere un pacchetto antirimbalzo npm nel mio progetto.

Quando ho provato la soluzione accettata sopra ho ottenuto un'eccezione:

L'assegnazione di importazione non può essere utilizzata quando si scelgono come target i moduli ECMAScript. Considera l'utilizzo di 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"' o un altro formato di modulo.

Questo ha finito per funzionare:

import debounce from 'debounce' 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.