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

Babel と TypeScript の ES6 modules の import の解釈の違い

More than 3 years have passed since last update.

概要

Babel と TypeScript の ES6 modules の import の挙動の違いについて確認する。 Application 内部では Babel ・ TypeScript を同一設定で使うはずなので問題は起きない。しかし、外部の npm package を利用する際には問題が起きる。

各状況ごとにどう書けばいいのかの参考情報をまとめる。

将来的には、このようなまとめが不要になることを期待する。

前提

  • Babel 6.6.5
    • es2015 preset
  • TypeScript 1.8.7
    • allowSyntheticDefaultImports (export = fooimport foo from 'foo'; できる)

各変換結果

1. Babel import ... from '...';

import foo from 'foo';

foo(1 === 1);
'use strict';

var _foo = require('foo');

var _foo2 = _interopRequireDefault(_foo);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

(0, _foo2.default)(1 === 1);

2. Babel import * as ... from '...';

import * as foo from 'foo';

foo(1 === 1);
'use strict';

var _foo = require('foo');

var foo = _interopRequireWildcard(_foo);

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }

foo(1 === 1);

3. TypeScript import ... from '...';

import foo from 'foo';

foo(1 === 1);
"use strict";
var foo_1 = require('foo');
foo_1["default"](1 === 1);

4. TypeScript import * as ... from '...';

import * as foo from 'foo';

foo(1 === 1);
"use strict";
var foo = require('foo');
foo(1 === 1);

実行結果

npm package の実装ごとに場合わけする。

1. ES6 module の考慮なし

function foo() { /* ... */ };
module.exports = foo;
// module.exports.default = foo;
// module.exports.__esModule = true;
  1. Babel import foo from 'foo'; は OK
  2. Babel import * as foo from 'foo'; は実行時 Error
  3. TypeScript import foo from 'foo'; は実行時 Error
  4. TypeScript import * as foo from 'foo'; は OK

いきなり矛盾している。ヤバイ。

2. ES6 module を考慮し、default に export

function foo() { /* ... */ };
module.exports = foo;
module.exports.default = foo;
// module.exports.__esModule = true;
  1. Babel import foo from 'foo'; は OK
  2. Babel import * as foo from 'foo'; は実行時 Error
  3. TypeScript import foo from 'foo'; は OK
  4. TypeScript import * as foo from 'foo'; は OK

これで 3. が OK になった。いい感じだ。

3. ES6 module を考慮し、default に export し、 __esModule を truthy に

function foo() { /* ... */ };
module.exports = foo;
module.exports.default = foo;
module.exports.__esModule = true;
  1. Babel import foo from 'foo'; は OK
  2. Babel import * as foo from 'foo'; は OK
  3. TypeScript import foo from 'foo'; は OK
  4. TypeScript import * as foo from 'foo'; は OK

__esModule が必要って時点でおかしいし、もう ES6 babel modules って呼べばいいんじゃないかな。

まとめ

ES6 modules を module.exports = function() { ... }; な外部 npm package に適用するときはよく注意する。import ... from '...';import * as ... from '...'; のどちらか一方しかきちんと動かないし、 Babel と TypeScript の解釈は矛盾しているため、それぞれ逆の記法が必要だ。

今回は問題にしなかったが TypeScript には .d.ts の問題や記法の解釈を変える option もある。がんばってほしい。→ TypeScript の ES6 modules の解釈と allowSyntheticDefaultImports の整理 - Qiita

補足

ES6 modules の仕様を見る限り、 Babel の挙動は間違っているように見える。ただ互換性の都合でそうなっていて、どうしようもないのかもしれない。

参考

bouzuya
ぼく、ぼうずや。なさけはひとのためならず。たのしいはせいぎ。
http://bouzuya.net/
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
ユーザーは見つかりませんでした