Help us understand the problem. What is going on with this article?

esModuleInterop オプションの必要性について

More than 1 year has passed since last update.

個人的にちょうど該当の問題を取り扱ったので、TypeScript 2.7.1 で導入された
esModuleInterop オプションの役割と背景についてまとめておく。

なお、本来は export と import の両方に影響するオプションだが、この記事では外部の npm パッケージを import する状況のみを取り上げる。

TL;DR

Node.js 環境で import/export を使う場合、

  • esModuleInterop オプションを積極的に有効にする。
  • 関数や class を export するモジュールを import する場合、import * as _ from '_' のかわりに import _ = require('_') を使う。

モジュールの互換性

先にTypeScript の ES6 modules の解釈と allowSyntheticDefaultImports の整理という記事を読んでおくとよい。

バックグラウンドとして知っておくべきは以下の2つ:

  1. ES6 Modules は Node.js のモジュール(CommonJS)との互換性について規定がない。
  2. ES6 Modules で import/export できるものは TypeScript でいう名前空間(ざっくりいうと識別子として使えるプロパティを持つプレーンなオブジェクト) にかぎられるが、CommonJS はそうした制限がない。

Babel V.S. TypeScript

上の事情のため、Node.js のモジュールをどう扱うかはビルドツールごとに独自の仕様が設けられている。

例えば、つぎのような math モジュールを取り込もうとすると、TypeScript と Babel で異なる書き方が必要だった。

node_modules/math/index.js
var math = {
  min: function (lhs, rhs) { ...}
};
module.exports = math;

Babel:

babel.js
import math from 'math';

math.min(1, 2);

TypeScript:

tsc.ts
import * as math from 'math';

math.min(1, 2);

いいかえると、 export 側のコードはそれぞれ以下の ES6 Module として解釈されている。

Babel:

function min(lhs, rhs) { ...}

export default {
  min,
};

TypeScript:

export function min(lhs, rhs) { ...}

esModuleInterop オプションはこの振る舞いを Babel に近づけるものと考えてよい。

関数やクラスの export 問題

では TypeScript 式の何が問題だったのかというと、すでにある CommonJS モジュールが class や function を export している場合に手詰まりになること。

例えば

node_modules/min/index.js
function min(lhs, rhs) { ... }
module.exports = min;

というモジュールがあったとして、以下のコードを babel に通して実行すると、実行時エラーになる。

import * as min from 'min';

min(2, 3);

どう解決されるのか

これに対して上のオプションをつけるとどうなるのか。

まず import * と 関数呼び出しの組み合わせがコンパイルエラーになるようになる。

正しく動かしたい場合、選択肢は二つある。

一つは、以前からある syntheticDefault オプションを使用すること。ただしこのオプションはあらゆるモジュールの import/export の振る舞いを変えてしまうため、おすすめしない。

もう一つは import = を使うこと。つまり以下のようにする。

import min = require('min');

もともと互換性がない以上、これが妥当だろう。実際、DefinitelyTyped はそうしている

参考

karak
最近は C#, TypeScript, React, Xamarin.Forms と AWS Lambda 界隈にいます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした