LoginSignup
93
75

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-03-15

概要

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 の挙動は間違っているように見える。ただ互換性の都合でそうなっていて、どうしようもないのかもしれない。

参考

93
75
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
93
75