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

TypeScript の ES6 modules の解釈と allowSyntheticDefaultImports の整理

More than 3 years have passed since last update.

概要

TypeScript (1.8.7) の次の項目の関連を整理する。

  • import foo from 'foo';
  • import * as foo from 'foo';
  • export default foo;
  • export = foo;
  • allowSyntheticDefaultImports option

TL;DR

  • allowSyntheticDefaultImports: false (default)
    • export = foo; / import * as foo from 'foo'; / module.exports = foo; が対応
    • export default foo; / import foo from 'foo'; / module.exports.default = foo; が対応
  • allowSyntheticDefaultImports: true
    • export = foo; / import * as foo from 'foo'; / module.exports = foo; が対応
    • export = foo; / export default foo; / import foo from 'foo'; / module.exports.default = foo; が対応

つまり、外部の npm package (module.exports = function foo() {};) を読み込む場合は、TypeScript 的には

  • option なし (default)
  • export = foo; という .d.ts
  • import * as foo from 'foo';

を使うのが良い。

外部の npm package が module.exports.default = foo; に対応している場合は、

  • option なし (default)
  • export default foo; という .d.ts
  • import foo from 'foo';

または

  • allowSyntheticDefaultImports: true
  • export = foo; という .d.ts (型定義を触れない場合など)
  • import foo from 'foo';

を使うのが良い。

ファイル

.d.ts

0.d.ts
declare module 'foo' {
  var foo: any;
  export = foo;
}
1.d.ts
declare module 'foo' {
  var foo: any;
  export default foo;
}

.ts

0.ts
import * as foo from 'foo';
foo(1 === 1);
1.ts
import foo from 'foo';
foo(1 === 1);

実行結果

option なし

$ $(npm bin)/tsc 0.d.ts 0.ts
$ $(npm bin)/tsc 0.d.ts 1.ts
1.ts(1,8): error TS1192: Module ''foo'' has no default export.
$ $(npm bin)/tsc 1.d.ts 0.ts
0.ts(2,1): error TS2349: Cannot invoke an expression whose type lacks a call signature.
$ $(npm bin)/tsc 1.d.ts 1.ts

この結果から TypeScript は次のように解釈していることが分かる。

  • export = foo; / import * as foo from 'foo'; / module.exports = foo; が対応
  • export default foo; / import foo from 'foo'; / module.exports.default = foo; が対応

--allowSyntheticDefaultImports あり

$ $(npm bin)/tsc --allowSyntheticDefaultImports 0.d.ts 0.ts
$ $(npm bin)/tsc --allowSyntheticDefaultImports 0.d.ts 1.ts
$ $(npm bin)/tsc --allowSyntheticDefaultImports 1.d.ts 0.ts
0.ts(2,1): error TS2349: Cannot invoke an expression whose type lacks a call signature.
$ $(npm bin)/tsc --allowSyntheticDefaultImports 1.d.ts 1.ts

この結果から TypeScript は次のように解釈を変えることが分かる。

  • export = foo; / import * as foo from 'foo'; / module.exports = foo; が対応
  • export = foo; / export default foo; / import foo from 'foo'; / module.exports.default = foo; が対応

export = foo;import * foo from 'foo'; だけでなく import foo from 'foo'; でも読めるようにする option なのだろう。

ちなみに import foo from 'foo'; の変換結果自体は option の有無に関係なく module.exports.default = foo; を想定して動くので、 npm package 側が対応していない場合はむやみに使うと危ないだろう。export = foo; という型定義になっており export default されていない場合にも、されているかのように解釈させる option なのだろう。

まとめ

TypeScript 的には (Babel は異なる →詳細は『Babel と TypeScript の ES6 modules の import の解釈の違い - Qiita』を参照)

外部の npm package (module.exports = function foo() {};) を読み込む場合は、

  • option なし (default)
  • export = foo; という .d.ts
  • import * as foo from 'foo';

を使うのが良い。

外部の npm package が module.exports.default = foo; に対応している場合は、

  • option なし (default)
  • export default foo; という .d.ts
  • import foo from 'foo';

または

  • allowSyntheticDefaultImports: true
  • export = foo; という .d.ts (型定義を触れない場合など)
  • import foo from 'foo';

を使うのが良い。

補足

export default foo;module.exports.default = foo; として扱うのは ES6 modules として正しい。http://www.ecma-international.org/ecma-262/6.0/#table-42 を見る限り export default foo;'default' key で export される foo (module.exports = { default: foo };)だからだ。それに対応する形だが import foo from 'foo';module.exports.default = foo;foo を使うのも正しい。http://www.ecma-international.org/ecma-262/6.0/#table-40 に表がある。

参考

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
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