typescript - Ce înseamnă „... se rezolvă într-o entitate non-modul și nu poate fi importată folosind această construcție”?
Am câteva fișiere 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();
Acest lucru îmi dă erori atunci când încerc să folosesc new
Modulul "MyClass" se rezolvă într-o entitate non-modul și nu poate fi importat folosind această construcție.
și atunci când încerc să apelez fn()
Nu se poate apela o expresie al cărei tip nu are o semnătură de apel.
Ce se întâmplă?
Răspuns #1
De ce nu funcționează
import * as MC from './MyClass';
Aceasta este sintaxa import de stil ES6/ES2015. Semnificația exactă a acestui lucru este „Ia obiectul namespace al modulului încărcat din ./MyClass și folosește-l local ca MC”. În mod notabil, „obiectul namespace al modulului” constă doar dintr-un obiect simplu cu proprietăți. Un obiect modul ES6 nu poate fi invocat ca o funcție sau cu new.
Ca să o spunem din nou: Un obiect namespace al unui modul ES6 nu poate fi apelat ca o funcție sau cu new.
Lucrul pe care îl importați folosind * as X dintr-un modul este definit să aibă doar proprietăți. În CommonJS coborât acest lucru s-ar putea să nu fie respectat pe deplin, dar TypeScript vă spune care este comportamentul definit de standard.
Ce funcționează?
Va trebui să folosești sintaxa de import de tip CommonJS pentru a utiliza acest modul:
import MC = require('./MyClass');
Dacă controlezi ambele module, poți folosi export default în schimb:
MyClass.ts
export default class MyClass {
constructor() {
}
}
MyConsumer.ts
import MC from './MyClass';
Sunt trist din cauza asta; regulile sunt stupide.
Ar fi fost frumos să folosesc sintaxa de import ES6, dar acum trebuie să fac acest lucru import MC=require('./MyClass');? Este atât de 2013! Jenant! Dar durerea este o parte normală a programării. Vă rugăm să treceți la etapa cinci a modelului Kübler-Ross: Acceptare.
TypeScript aici îți spune că asta nu funcționează, pentru că chiar nu funcționează. Există trucuri (adăugarea unei declarații namespace la MyClass este o modalitate populară de a pretinde că funcționează), și ele ar putea să funcționeze azi în modulul tău specific de downleveling (de exemplu rollup), dar aceasta este iluzorie. Nu există încă implemetări ES6 module în sălbăticie, dar asta nu va fi adevărat pentru totdeauna.
Imaginează-ți viitorul tău eu, încercând să rulezi pe o implementare nativă ES6 și descoperind că ți-ai pregătit singur un eșec major prin încercarea de a folosi sintaxa ES6 pentru a face ceva ce ES6 nu face în mod explicit.
Vreau să profit de încărcătorul meu de module non-standard
Poate că ai un încărcător de module care „ajutător” creează exporturi default atunci când nu există niciunul. Adică, oamenii fac standarde dintr-un motiv, dar ignorarea standardelor este uneori distractivă și putem să ne gândim că este un lucru tare de făcut.
Schimbă MyConsumer.ts în:
import A from './a';
Și specificați opțiunea de linie de comandă sau tsconfig.json allowSyntheticDefaultImports.
Rețineți că allowSyntheticDefaultImports nu schimbă deloc comportamentul la rulare al codului dumneavoastră. Este doar un indicator care spune TypeScript că încărcătorul de module creează exporturi default atunci când nu există. Nu va face minuni ca codul dvs. să funcționeze în nodejs dacă nu funcționa înainte.
Răspunsul #2
TypeScript 2.7 introduce suport prin emiterea de noi metode ajutătoare: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#support-for-import-d-from-cjs-form-commonjs-modules-with---esmoduleinterop
Deci în tsconfig.json adaugă aceste două setări:
{
// 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
}
Și acum poți folosi:
import MyClass from './MyClass';
