JavaScript - ნაგულისხმევი კლასის ინსტანცირება იწვევს TypeError-ს (ESM/CJS ინტერპაპი)
პრობლემის არსში
გამარჯობათ,
მომაქვს TypeScript პროექტი, სადაც ვცდილობ კლასის ინიციალიზაციას, რომელიც იყო სხვადასხვა პაკეტის სტანდარტული ექსპორტი. მე ვწერ ჩემს პროექტს ESM სინტაქსით, ხოლო პაკეტი, რაზეც ის არის დამოკიდებული, აქვს CJS გამომავალი. პრობლემა, რომლის წინაშეც ვდგავარ, ის არის, რომ შესრულების დროს, როდესაც შესრულების ნაკადი ცენტრალიზდება კლასის ინიციალიზაციის წერტილზე, ვიღებ შემდეგ შეცდომას -
new TestClass({ arg1: "Hello, World!" });
^
TypeError: TestClass is not a constructor
კოდი
//My package.json
{
"name": "myproject",
"version": "1.0.0",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js"
},
"type": "module",
"dependencies": {
"testpackage": "^1.0.0",
"typescript": "^5.0.4"
},
"devDependencies": {
"@types/node": "^20.2.5"
}
}
//My index.ts
import TestClass from "testpackage";
new TestClass({ arg1: "Hello, World!" });
//My tsconfig.json
{
"include": ["src"],
"compilerOptions": {
"outDir": "dist",
"lib": ["es2023"],
"target": "es2022",
"moduleResolution": "node"
}
}
//Dependency's package.json
{
"name": "testpackage",
"version": "1.0.0",
"description": "TestPackage",
"main": "./dist/testFile.js",
"exports": "./dist/testFile.js",
"scripts": {
"build": "tsc"
},
"files": ["dist"],
"devDependencies": {
"@types/node": "^20.2.5",
"typescript": "^5.0.4"
}
}
//Dependency's testFile.ts
export default class TestClass {
constructor({ arg1 }: { arg1: string }) {
console.log(arg1);
}
}
//Dependency's tsconfig.json
{
"include": ["src"],
"compilerOptions": {
"declaration": true,
"lib": ["es2023"],
"target": "es6",
"module": "CommonJS",
"outDir": "dist"
}
}
//Dependency's testFile.js output
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class TestClass {
constructor({ arg1 }) {
console.log(arg1);
}
}
exports.default = TestClass;
ყველაფერი კარგად მუშაობს, თუ მე ვწავშლი "type": "module" ჩემს package.json-დან. ასევე ყველაფერი კარგად მუშაობს, თუ კლასი არის ნამდვილი ნავაშვებო ექსპორტი CJS-ის კოდის ნაცვლად. ეს ცნობილია არასამუშაოობას, როდესაც ცდილობენ CJS-ის იმპორტირებას ESM-ში, თუ მე არასწორად ვაკეთებ აქ რაღაცას?
შენიშვნა - თუ ჩემს tsconfig.json-ში დავაყენებ "moduleResolution": "nodenext", მაშინ შეცდომა წარმოიქმნება პირდაპირ კრებულის დროს -
src/index.ts:3:5 - error TS2351: This expression is not constructable.
Type 'typeof import("<project_dir>/node_modules/testpackage/dist/testFile")' has no construct signatures.
3 new TestClass({ arg1: "Hello, World!" });
~~~~~~~~~
Found 1 error in src/index.ts:3
პასუხი #1
არსებობს ცნობილი შესაბამისობის პრობლემები CommonJS (CJS) და ECMAScript მოდულებს (ESM) შორის. ESM-ში, CJS მოდულების დეფოლტური ექსპორტები იყოფა default თვისებებში პირდაპირი გამოქვეყნების ნაცვლად. მეორეს მხრივ, დასახელებული ექსპორტები არ მოქმედებს და შესაძლებელია მათი პირდაპირი იმპორტირება.
თუ თქვენ მიუთითებთ "type": package.json-ში, რაც მიუთითებს "module"-ზე, Node.js-ს აიძულებს .js ფაილის ESM-ისად ითხოვოს. შესაბამისად, თქვენ უნდა იმპორტოთ მოდული ESM იმპორტის განცხადებით. თუმცა, თუ მოდული, რომლის იმპორტზეც ცდილობთ, არის CJS ფორმატში, ეს გამოიწვევს თავსებადობის პრობლემებს.
არსებობს რამდენიმე შესაძლებლობა ამისა გამოსასწორებლად.
- მოიძიეთ კლასი სტანდარტული თვისების საშუალებით, როგორც ზემოთ აღინიშნა.
import Test from 'package-name';
const TestClass = Test.default;
ორივე მოდულის ფორმატის შერევის შედეგად წარმოქმნილი პრობლემების თავიდან ასაცილებლად, ყველა კოდი გადაიყვანეთ ან ESM-ის, ან CJS-ის გამოყენებაზე.
ჩატვირთეთ CJS მოდული Node.js createRequire ფუნქციის გამოყენებით.
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const TestClass = require('package-name');
