2 votes

La création d'instance de classe par défaut entraîne une TypeError (interop ESM/CJS)

Résumé du Problème

Bonjour,

J'ai un projet TypeScript dans lequel j'essaie d'instancier une classe qui était l'export par défaut d'un autre package. J'écris mon projet en syntaxe ESM, tandis que le package sur lequel il dépend a une sortie CJS. Le problème que je rencontre est que lors de l'exécution, lorsque le flux atteint le point d'instanciation de la classe, je reçois l'erreur suivante -

new TestClass({ arg1: "Bonjour, le Monde !" });
^

TypeError: TestClass n'est pas un constructeur

Code

//Mon package.json
{
  "name": "monprojet",
  "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"
  }
}

//Mon index.ts
import TestClass from "testpackage";

new TestClass({ arg1: "Bonjour, le Monde !" });

//Mon tsconfig.json
{
    "include": ["src"],
    "compilerOptions": {
        "outDir": "dist",
        "lib": ["es2023"],
        "target": "es2022",
        "moduleResolution": "node"
    }
}

//package.json de la Dépendance
{
    "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"
    }
}

//testFile.ts de la Dépendance
export default class TestClass {
    constructor({ arg1 }: { arg1: string }) {
        console.log(arg1);
    }
}

//tsconfig.json de la Dépendance
{
    "include": ["src"],
    "compilerOptions": {
        "declaration": true,
        "lib": ["es2023"],
        "target": "es6",
        "module": "CommonJS",
        "outDir": "dist"
    }
}

//Sortie testFile.js de la Dépendance
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class TestClass {
    constructor({ arg1 }) {
        console.log(arg1);
    }
}
exports.default = TestClass;

Les choses fonctionnent bien si je supprime "type": "module" de mon package.json. Elles fonctionnent également bien si la classe est une exportation nommée au lieu d'une exportation par défaut dans le code de la dépendance. Est-ce une incompatibilité connue lors de la tentative d'importation de CJS dans ESM ou est-ce que je fais quelque chose de incorrect ici ?


Remarque - Si je définis "moduleResolution": "nodenext" dans mon tsconfig.json alors l'erreur est générée dès la compilation -

src/index.ts:3:5 - error TS2351: Cette expression n'est pas constructible.
  Le type 'typeof import("/node_modules/testpackage/dist/testFile")' n'a pas de signatures de construction.

3 new TestClass({ arg1: "Bonjour, le Monde !" });
      ~~~~~~~~~

Trouvé 1 erreur dans src/index.ts:3

2voto

MWY Points 370

Il existe des problèmes de compatibilité connus entre CommonJS (CJS) et les modules ECMAScript (ESM). En ESM, les exports par défaut des modules CJS sont enveloppés dans des propriétés par défaut au lieu d'être exposés directement. En revanche, les exports nommés ne sont pas affectés et peuvent être importés directement.

Si vous spécifiez "type": Spécifier "module" dans package.json fait que Node.js traite le fichier .js comme son ESM. Par conséquent, vous devez importer le module en utilisant l'instruction d'import ESM. Cependant, si le module que vous essayez d'importer est au format CJS, vous rencontrerez des problèmes de compatibilité.

Il existe plusieurs options pour résoudre ce problème.

  1. Accédez à la classe via la propriété par défaut comme décrit ci-dessus.

    import Test from 'package-name'; const TestClass = Test.default;

  2. Pour éviter les problèmes causés par le mélange des deux formats de modules, convertissez tout le code pour utiliser soit ESM, soit CJS.

  3. Chargez le module CJS en utilisant la fonction createRequire de Node.js.

    import { createRequire } from 'module'; const require = createRequire(import.meta.url); const TestClass = require('package-name');

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X