tsconfigファイルのesModuleInteropについて


142

私は誰かの.tsconfigファイルをチェックアウトしていて、そこで見つけました--esModuleInterop

これは彼の.tsconfigファイルです

{
  "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"]
}

ここでは、私の主な質問は何であるかである "esModuleInterop": true,と "allowSyntheticDefaultImports": true,。私は彼らが一種に依存していることを知っています "module": "commonjs",。誰かがそれを可能な限り最高の人間の言語で説明しようとすることができますか?

allowSyntheticDefaultImports州の公式ドキュメント

デフォルトのエクスポートなしでモジュールからのデフォルトのインポートを許可します。これはコードの発行には影響せず、型チェックだけに影響します。

それは〜を意味しますか?エクスポートのデフォルトがない場合、インポートのデフォルトの唯一の使用例は何かを初期化することだと思いますか?シングルトンのように?

次の質問/回答も意味がありません フラグであるのではなく、tsconfigで--esModuleInteropを使用する方法はありますか?

そして--esModuleInteropコンパイラページでの定義

ランタイムバベルエコシステムの互換性のために__importStarおよび__importDefaultヘルパーを発行し、タイプシステムの互換性のために--allowSyntheticDefaultImportsを有効にします。

また、理解/理解するのが難しいようでした

回答:


169

問題文

CommonJSモジュールをES6モジュールのコードベースにインポートするときに問題が発生します。

これらのフラグの前に、スター(* as something)インポートを使用してCommonJSモジュールをインポートする必要がありました。

// 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();

私たちは、それが見ることができます*何とかと同等であったexports変数。正常に動作しましたが、es6モジュールの仕様に準拠していませんでした。仕様では、スターインポートのネームスペースレコード(momentこの場合)はプレーンオブジェクトのみであり、呼び出し可能でmoment()はありません(許可されていません)。

解決

フラグesModuleInteropを使用すると、es6モジュール仕様に準拠してCommonJSモジュールをインポートできます。インポートコードは次のようになります。

// 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();

これは機能し、es6モジュール仕様で完全に有効ですmoment。スターインポートの名前空間ではないため、デフォルトのインポートです。

しかし、それはどのように機能しますか?ご覧のとおり、デフォルトのインポートを行ったのでdefault、momentオブジェクトのプロパティを呼び出します。しかし、モーメントライブラリdefaultではexportsオブジェクトのプロパティを宣言していません。キーは__importDefault機能しています。CommonJSモジュールのプロパティにモジュール(exports)を割り当てdefaultます。

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

ご覧のとおり、es6モジュールはそのままインポートしていますが、CommonJSモジュールはdefaultキーでオブジェクトにラップされています。これにより、CommonJSモジュールのデフォルトをインポートできます。

__importStar同様の仕事をします-それはそのままのesModulesを返しますが、CommonJSモジュールを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;
};

合成輸入

そしてallowSyntheticDefaultImports、それは何のためですか?これでドキュメントが明確になります:

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

でmoment、それが唯一のフラグで使用可能ですbeacuseタイピングは、デフォルトのエクスポートを指定していないし、我々は持つべきではありませんesModuleInteropの。したがって、allowSyntheticDefaultImportsデフォルトのエクスポートを持たないサードパーティモジュールからデフォルトをインポートする場合は、エラーを報告しません。


導入に先立ち--esModuleInteropフラグ、import * as moment from 'moment'だったではないが正しいです。import moment = require('moment')だった。
— アルアンハダード

14

esModuleInteropドキュメントで概説されているヘルパーを生成します。生成されたコードを見ると、これらの機能が正確にわかります。

//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:モジュールがモジュールではない場合、esrequireによって返されるものがデフォルトになります。つまり、commonjsモジュールでデフォルトのインポートを使用すると、モジュール全体が実際にデフォルトになります。

__importStarこのPRで最もよく説明されています:

TypeScriptは、ネームスペースのインポート(つまりimport * as foo from "foo")をと同等のものとして扱いますconst foo = require("foo")。物事はここでは単純ですが、インポートされるプライマリオブジェクトがプリミティブまたは呼び出し/構成シグネチャを持つ値である場合はうまくいきません。ECMAScriptは基本的に名前空間レコードはプレーンオブジェクトであると述べています。

Babelはまずモジュールで要求し、という名前のプロパティをチェックします__esModule。__esModuleがに設定されている場合true、動作はTypeScriptの動作と同じですが、それ以外の場合は、次の名前空間レコードを合成します。

  1. すべてのプロパティはrequire'dモジュールから引き抜かれ、名前付きインポートとして利用可能になります。
  2. 元々必要だったモジュールはデフォルトのインポートとして利用可能になります。

したがって、これを取得します。

// 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"));

allowSyntheticDefaultImportsこれすべてのコンパニオンです。これをfalseに設定しても、放出されたヘルパーは変更されません(両方とも同じように見えます)。ただし、commonjsモジュールにデフォルトのインポートを使用している場合は、typescriptエラーが発生します。これはimport React from 'react'エラーが発生しますModule '".../node_modules/@types/react/index"' has no default export.場合allowSyntheticDefaultImportsですfalse。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.