Tsconfig dosyasında esModuleInterop'u anlama


142

Birini kontrol ediyordum .tsconfig dosyasını ve orada gördüm--esModuleInterop

Bu onun .tsconfigdosyası

{
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "es6",
    "module": "commonjs",
    "lib": ["esnext"],
    "strict": true,
    "sourceMap": true,
    "declaration": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "declarationDir": "./dist",
    "outDir": "./dist",
    "typeRoots": ["node_modules/@types"]
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modues"]
}

Burada birincil sorum nedir "esModuleInterop": true,ve nedir "allowSyntheticDefaultImports": true,? Bir bakıma bağımlı olduklarını biliyorum "module": "commonjs",. Birisi bunu mümkün olan en iyi insan dilinde açıklamaya çalışabilir mi?

allowSyntheticDefaultImportsEyaletler için resmi belgeler

Varsayılan dışa aktarım olmadan modüllerden varsayılan içe aktarmaya izin verin. Bu kod yaymayı etkilemez, sadece yazım denetimi yapar.

Bu demek mi? İçe aktarma varsayılanının tek kullanım durumunun bir şeyi başlatmak olacağını düşündüğümden herhangi bir ihracat varsayılanı yoksa? singleton gibi mi?

Aşağıdaki soru / cevap da mantıklı değil --esModuleInterop'u tsconfig'te bayrak olmasının aksine kullanmanın bir yolu var mı?

Ve --esModuleInteropderleyici sayfasındaki tanım

Çalışma zamanı babel ekosistemi uyumluluğu için __importStar ve __importDefault yardımcıları yayınlayın ve tür sistemi uyumluluğu için --allowSyntheticDefaultImports'u etkinleştirin.

Ayrıca anlamak / anlamak benim için zor görünüyordu

Yanıtlar:


175

Sorun bildirimi

CommonJS modülünü ES6 modülü kod tabanına aktarmak istediğimizde sorun oluşur.

Bu bayraklardan önce, CommonJS modüllerini yıldız ( * as something) içe aktarmalı içe aktarmamız gerekiyordu :

// node_modules/moment/index.js
exports = moment
// index.ts file in our app
import * as moment from 'moment'
moment(); // not compliant with es6 module spec

// transpiled js (simplified):
const moment = require("moment");
moment();

Bunun bir *şekilde exportsdeğişkene eşdeğer olduğunu görebiliriz . İyi çalıştı, ancak es6 modülleri spesifikasyonuyla uyumlu değildi. Spesifikasyonda, yıldız içe aktarmadaki ad alanı kaydı ( momentbizim durumumuzda) yalnızca düz bir nesne olabilir, çağrılamaz (moment() izin verilmez).

Çözüm

Bayrak ile esModuleInterop, CommonJS modüllerini es6modül özelliklerine uygun olarak içe aktarabiliriz . Şimdi ithalat kodumuz şöyle görünüyor:

// index.ts file in our app
import moment from 'moment'
moment(); // compliant with es6 module spec

// transpiled js with esModuleInterop (simplified):
const moment = __importDefault(require('moment'));
moment.default();

Çalışır ve es6 modülleri spesifikasyonuyla mükemmel bir şekilde geçerlidir, çünkü momentyıldız içe aktarmadan gelen ad alanı değildir, varsayılan içe aktarımdır .

Ama nasıl çalışıyor? Gördüğünüz gibi, varsayılan içe aktarma yaptığımız için default, momentnesnede özellik olarak adlandırıyoruz . Ancak moment kütüphanesindeki nesne defaultüzerinde herhangi bir özellik beyan etmedik exports. Anahtar __importDefaultişlevde. CommonJS modüllerinin özelliğine module ( exports) atar default:

var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};

Gördüğünüz gibi es6 modüllerini olduğu gibi içe aktarıyoruz, ancak CommonJS modülleri defaultanahtarla nesneye sarılıyor . Bu, CommonJS modüllerinde varsayılanları içe aktarmayı mümkün kılar.

__importStarbenzer işi yapar - dokunulmamış esModules döndürür, ancak CommonJS modüllerini özelliğe sahip modüllere çevirir default:

// index.ts file in our app
import * as moment from 'moment'

// transpiled js with esModuleInterop (simplified):
const moment = __importStar(require("moment"));
// note that "moment" is now uncallable - ts will report error!
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};

Sentetik ithalatlar

Peki ya allowSyntheticDefaultImports, ne için? Şimdi dokümanlar açık olmalı:

Allow default imports from modules with no default export. This does not affect code emit, just typechecking.

Gelen momenttypings biz belirtilen varsayılan ihracat yok ve sadece bayrağıyla kullanılabilir beacuse biz olmamalıdır esModuleInteropüzerinde. Bu nedenle allowSyntheticDefaultImports, varsayılan dışa aktarımı olmayan üçüncü parti modülünden varsayılanı içe aktarmak istiyorsak hata bildirmeyeceğiz.


Getirilmesinden önce --esModuleInteropbayrak, import * as moment from 'moment'oldu değil doğru. import moment = require('moment')oldu.
Aluan Haddad

15

esModuleInteropDokümanlarda ana hatları verilen yardımcıları üretir. Oluşturulan koda baktığımızda, bunların tam olarak ne işe yaradığını görebiliriz:

//ts 
import React from 'react'
//js 
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = __importDefault(require("react"));

__importDefault: Modül bir esmodül değilse , gereksinim tarafından döndürülen şey varsayılan olur. Bu, bir commonjsmodülde varsayılan içe aktarmayı kullanırsanız , tüm modülün aslında varsayılan olduğu anlamına gelir .

__importStaren iyi bu PR'da açıklanmaktadır :

TypeScript, bir ad alanı içe aktarımını (yani import * as foo from "foo") ile eşdeğer olarak ele alır const foo = require("foo"). Burada işler basit, ancak içe aktarılan birincil nesnenin ilkel mi yoksa çağrı / inşa imzaları olan bir değer mi olduğu çözülemiyor. ECMAScript temel olarak bir ad alanı kaydının düz bir nesne olduğunu söyler.

Babel önce modülde gerektirir ve adlı bir özelliği kontrol eder __esModule. Olarak __esModuleayarlanırsa true, davranış TypeScript'inkiyle aynıdır, ancak aksi takdirde, bir ad alanı kaydını sentezler, burada:

  1. Tüm özellikler gerekli modülden çıkarılır ve adlandırılmış içe aktarmalar olarak sunulur.
  2. Başlangıçta gerekli olan modül, varsayılan bir içe aktarma olarak kullanıma sunulur.

Böylece şunu anlıyoruz:

// ts
import * as React from 'react'

// emitted js
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
var React = __importStar(require("react"));

allowSyntheticDefaultImportstüm bunların yoldaşıdır, bunu yanlış olarak ayarlamak gönderilen yardımcıları değiştirmez (ikisi de aynı görünecektir). Ancak, bir commonjs modülü için varsayılan içe aktarmayı kullanıyorsanız, bu bir typcript hatası oluşturacaktır. Yani bu import React from 'react'hatayı yükseltecektir Module '".../node_modules/@types/react/index"' has no default export.eğer allowSyntheticDefaultImportsolduğunu false.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.