概要
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
declare module 'foo' {
var foo: any;
export = foo;
}
declare module 'foo' {
var foo: any;
export default foo;
}
.ts
import * as foo from 'foo';
foo(1 === 1);
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 に表がある。