1. ホーム
  2. typescript

[解決済み】tsconfigファイルにおけるesModuleInteropの理解

2022-02-10 22:10:07

質問

ある人を調べていたら .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 を有効にしてください。 タイプシステムの互換性。

また、私には理解するのが難しいようです。

どのように解決するのですか?

問題提起

ES6モジュールのコードベースにCommonJSモジュールをインポートしたい場合に問題が発生する。

これらのフラグが付く前は、CommonJSモジュールをインポートする際には、星印( * as something ) をインポートします。

// 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モジュールの仕様に準拠していませんでした。specでは、star importのnamespaceレコード( moment は、プレーンなオブジェクトのみで、呼び出し可能なものではありません ( moment() は不可)。

解決方法

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

// 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 は、star import の namespace ではなく、default import です。

しかし、どのように動作するのでしょうか?見ての通り、デフォルトのインポートを行ったので、その際に default プロパティに moment オブジェクトを作成します。しかし、私たちは default プロパティは exports オブジェクトを作成します。キーは __importDefault 関数があります。これは、モジュール( 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 というのも、このフラグは esModuleInterop をオンにしています。ですから allowSyntheticDefaultImports は、デフォルトのエクスポートを持たないサードパーティモジュールからデフォルトをインポートしたい場合、エラーを報告しません。