“ …แก้ไขเป็นเอนทิตีที่ไม่ใช่โมดูลและไม่สามารถนำเข้าโดยใช้โครงสร้างนี้ได้” หมายความว่าอย่างไร


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
Estus Flask

คำตอบ:


159

ทำไมมันไม่ทำงาน

import * as MC from './MyClass';

นี่คือimportไวยากรณ์สไตล์ ES6 / ES2015 ความหมายที่แท้จริงของสิ่งนี้คือ "นำอ็อบเจ็กต์เนมสเปซโมดูลที่โหลดจาก./MyClassและใช้ในเครื่องเป็นMC" โดยเฉพาะอย่างยิ่ง "โมดูลเนมสเปซอ็อบเจ็กต์ " ประกอบด้วยอ็อบเจ็กต์ธรรมดาที่มีคุณสมบัติเท่านั้น ไม่สามารถเรียกใช้อ็อบเจ็กต์โมดูล ES6 เป็นฟังก์ชันหรือด้วยnew.

จะบอกว่ามันอีกครั้ง: ES6 โมดูล namespace 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เป็นวิธีที่นิยมในการแสร้งทำเป็นว่างานนี้) และอาจใช้ได้ผลในวันนี้ในชุดรวมโมดูลการลดระดับของคุณโดยเฉพาะ (เช่นการรวม) แต่นี่เป็นภาพลวงตา ยังไม่มีการติดตั้งโมดูล ES6 ใด ๆ ในป่า แต่จะไม่เป็นจริงตลอดไป

ภาพตัวเองในอนาคตของคุณพยายามที่จะใช้ในการดำเนินงาน Neato พื้นเมืองโมดูล ES6 และพบว่าคุณได้ตั้งตัวเองขึ้นสำหรับความล้มเหลวที่สำคัญโดยพยายามที่จะใช้ไวยากรณ์ ES6 จะทำสิ่งที่ ES6 อย่างชัดเจนไม่ได้ทำ

ฉันต้องการใช้ประโยชน์จากตัวโหลดโมดูลที่ไม่ได้มาตรฐานของฉัน

บางทีคุณอาจมีตัวโหลดโมดูลที่ "ช่วยได้" สร้างการdefaultส่งออกเมื่อไม่มีอยู่ ฉันหมายถึงคนสร้างมาตรฐานด้วยเหตุผล แต่การละเลยมาตรฐานเป็นเรื่องสนุกในบางครั้งและเราคิดว่านั่นเป็นสิ่งที่ดีที่ต้องทำ

เปลี่ยนMyConsumer.tsเป็น:

import A from './a';

และระบุallowSyntheticDefaultImportsบรรทัดคำสั่งหรือtsconfig.jsonตัวเลือก

โปรดทราบว่าallowSyntheticDefaultImportsจะไม่เปลี่ยนพฤติกรรมรันไทม์ของโค้ดของคุณเลย เป็นเพียงแฟล็กที่บอก TypeScript ว่าตัวโหลดโมดูลของคุณสร้างdefaultเอ็กซ์พอร์ตเมื่อไม่มีอยู่ มันจะไม่ทำให้โค้ดของคุณทำงานใน nodejs ได้อย่างน่าอัศจรรย์เมื่อก่อนหน้านี้


สไตล์ commonjs ไม่จำเป็นต้องมีเป้าหมาย commonjs ใช่หรือไม่? มีวิธีทำให้งานนี้เมื่อคุณกำหนดเป้าหมาย es6 / es2015 หรือไม่?
Steve Buzonas

คุณไม่สามารถกำหนดเป้าหมาย ES6 ได้เนื่องจากไม่ทำงานใน ES6 ...
Ryan Cavanaugh

ฉันเข้าใจถูกต้องหรือไม่ว่าหากฉันกำหนดเป้าหมายโมดูล ES2015 จะไม่มีวิธีอ้างอิงโมดูล CommonJS ที่มีexport = MyClass? ทางเลือกเดียวของฉันคือตั้งค่าโมดูลของฉันcommonjsและทำให้โลกแย่ลงต่อไปโดยไม่ใช้ ES ที่ทันสมัย?
Micah Zoltu

6
ในบันทึกประจำรุ่น 2.7ภายใต้--esModuleInteropระบุว่า "เราขอแนะนำอย่างยิ่งให้ใช้ทั้งกับโครงการใหม่และโครงการที่มีอยู่" ในความคิดของฉันคำตอบนี้ (และรายการคำถามที่พบบ่อย / นโยบายในDefinitelyTypedลิงก์นั้น) ควรได้รับการแก้ไขเพื่อให้สอดคล้องกับจุดยืนใหม่
Alec Mev

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-module-with - 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และมันก็ใช้ได้ผลสำหรับฉัน
Edgar Quintero

6

การเพิ่ม 2 เซ็นต์ของฉันที่นี่ในกรณีที่มีคนอื่นมีปัญหานี้

วิธีของฉันในการแก้ไขปัญหาโดยไม่แก้ไขtsconfig.json(ซึ่งอาจเป็นปัญหาในบางโครงการ) ฉันได้ปิดการใช้งานกฎสำหรับ oneline

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


5

ฉันได้รับข้อผิดพลาดนี้เมื่อพยายามรวมแพ็คเกจการดีบัก npm ในโครงการของฉัน

เมื่อฉันลองวิธีแก้ปัญหาที่ยอมรับข้างต้นฉันได้รับข้อยกเว้น:

ไม่สามารถใช้การมอบหมายการนำเข้าเมื่อกำหนดเป้าหมายโมดูล ECMAScript ลองใช้ "import * เป็น ns จาก" mod "", "import {a} จาก" mod "", "import d จาก" mod "'หรือรูปแบบโมดูลอื่นแทน

สิ่งนี้ได้ผล:

import debounce from 'debounce' 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.