Ce face esModuleInterop
Multe pachete npm vechi sunt CommonJS: exportă o singură valoare cu module.exports = .... În modulele ES, ai vrea să le imporți cu import salut from "salut". Fără ajutor, codul generat pentru CommonJS caută .default, care nu există, și programul se oprește cu TypeError.
esModuleInterop rezolvă ambele părți: tsc permite importul implicit (pornește automat allowSyntheticDefaultImports) și adaugă în JavaScript funcții ajutătoare (__importDefault, __importStar) care fac importul să funcționeze la rulare. allowSyntheticDefaultImports singur permite doar scrierea, la verificare, fără să schimbe JavaScript-ul generat; e util când altă unealtă (bundler) face conversia.
Implicit, esModuleInterop este false, dar devine true pentru module node16/node18/node20/nodenext/preserve. allowSyntheticDefaultImports este true când esModuleInterop este pornit sau module este system. Pentru cod nou, lasă-l pornit.
Parametri
| Parametru | Descriere |
|---|---|
esModuleInterop: true |
Permite importul implicit și generează cod ajutător pentru CommonJS. |
allowSyntheticDefaultImports: true |
Doar permite import x from pentru module fără export default; nu schimbă JavaScript-ul generat. |
Exemple
Exemplul 1: Pachet CommonJS, fără și cu esModuleInterop
Pachetul salut exportă o funcție cu module.exports, iar declarația lui folosește export =. Fără opțiune, tsc refuză importul implicit. Cu opțiunea, codul generat folosește __importDefault și programul rulează.
// node_modules/salut/index.js
module.exports = function (nume) {
return "Salut, " + nume + "!";
};
// node_modules/salut/index.d.ts
declare function salut(nume: string): string;
export = salut;
// tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"target": "es2022",
"esModuleInterop": true
}
}
// index.ts
import salut from "salut";
console.log(salut("Ana"));
Rezultat (tsc 5.9)
$ npx tsc --esModuleInterop false
index.ts(1,8): error TS1259: Module '"/proiect/node_modules/salut/index"' can only be default-imported using the 'esModuleInterop' flag
$ npx tsc && cat index.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const salut_1 = __importDefault(require("salut"));
console.log((0, salut_1.default)("Ana"));
$ node index.js
Salut, Ana!
Exemplul 2: Doar allowSyntheticDefaultImports
Cu "esModuleInterop": false și "allowSyntheticDefaultImports": true, tsc acceptă importul, dar nu adaugă __importDefault. Fără un bundler care să facă conversia, programul se oprește.
// tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"target": "es2022",
"esModuleInterop": false,
"allowSyntheticDefaultImports": true
}
}
Rezultat (tsc 5.9)
$ npx tsc && cat index.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const salut_1 = require("salut");
console.log((0, salut_1.default)("Ana"));
$ node index.js 2>&1 | grep -m1 Error
TypeError: (0 , salut_1.default) is not a function
Exemplul 3: Import implicit dintr-un modul Node.js
Modulele încorporate din Node.js sunt CommonJS. Cu module: nodenext (care pornește esModuleInterop), importul implicit funcționează.
import path from "node:path";
import util from "node:util";
console.log(path.join("documente", "facturi", "ianuarie.pdf"));
console.log(path.basename("/home/ana/poze/iasi.jpg", ".jpg"));
console.log(util.format("%s are %d ani", "Ana", 25));
Rezultat
documente/facturi/ianuarie.pdf
iasi
Ana are 25 ani
Greșeli frecvente
- Să scrii
import * as salut from "salut"și să apelezisalut(). CuesModuleInterop, tsc dă eroarea TS2497: obiectul de namespace nu poate fi apelat; folosește importul implicit. - Să pornești doar
allowSyntheticDefaultImportscând tsc generează și JavaScript-ul. Verificarea trece, rularea nu.
Comenzi înrudite
module: Alege formatul de module din JavaScript-ul generat (ES modules, CommonJS) și regulile de import pe care le verifică tsc.verbatimModuleSyntax: Importurile rămân exact cum sunt scrise; se șterg doar cele marcate cu type, deci tipurile trebuie importate cu import type.importHelpers: Ia funcțiile ajutătoare (__awaiter, __decorate…) din pachetul tslib, în loc să le copieze în fiecare fișier.allowUmdGlobalAccess: Permite folosirea unei biblioteci UMD ca variabilă globală dintr-un fișier care este modul (are import/export).