js-primerというJavaScriptの本を書く上でES2015のimport/export構文の仕様について気になったところがあって調べたメモ
import - JavaScript | MDN https://t.co/qF0RdE0PfX
— lacolaco (@laco2net) June 26, 2018
デフォルトエクスポートをdefaultって名前付きエクスポートのように参照するのってmdnに載ってないけどESの仕様にあるんだっけ。TSの独自仕様?
import { default as foo } の構文
https://t.co/Qu54xh7HIj 読んでるけどIdenfierNameがdefaultのとき、っていう特別ケースの記述は無い気がするな。exportのほうに書かれてるんだろうか
— lacolaco (@laco2net) June 26, 2018
https://t.co/M6c93ISto6
— lacolaco (@laco2net) June 26, 2018
ここでデフォルトエクスポートしたらExportNameが"default"になるって書かれてるからそれは自明ってことかな
でもこれだと import { default } from でシンタックスエラーになる説明がされない気がするな。defaultがキーワードだから?でもdefault as で使えるならImportNameとしてvalidってことじゃないのか。よくわからない
— lacolaco (@laco2net) June 26, 2018
https://t.co/EPwMVhAsl6
— lacolaco (@laco2net) June 26, 2018
import { default }だとidentifierNameかつImportedBindingになって、こっちの予約語のルールがあるのでImportedBindingの名前としてdefaultは使えないが、default as とするとシンボルではなくidentiferNameとしてだけ使われるようになるからvalid、ということか。難しい
デフォルトエクスポートの扱い
まず、デフォルトエクスポートする方法がふたつある。ひとつは専用のexport default
文によってエクスポートする方法。
export default function () {}
また、default
という名前で名前付きエクスポートすれば、それもデフォルトエクスポートしたことになる。
function foo() {} export { foo as default };
デフォルトエクスポートがdefault
という固有名がつけられることは、Specの
https://www.ecma-international.org/ecma-262/6.0/#sec-exports-static-semantics-exportentries にかかれている。
デフォルトエクスポートをインポートする方法
デフォルトエクスポートされたものをインポートする方法もいくつかある。ひとつは一番シンプルなデフォルトインポート用の専用構文を使う。
import otherDefault from "other.js";
ところでこれは名前付きインポートで次のように書き換えられる。先程デフォルトエクスポートで書いたように、デフォルトエクスポートはdefault
という固有名でエクスポートされていることを利用できる。
import { default as otherDefault } from "other.js";
この構文、MDNのimport文のところには書かれていない。
ちなみに、default as
というのは専用の構文ではなく、as
によるエイリアス付きインポートの構文が適用されており、仕様上ではdefault
は特別なキーワードではなくただのIdentifierNameとして扱われているはず。
次のコードでdefaultとfooは仕様上同じもので区別できない。
import { default as otherDefault, foo as otherFoo } from "other.js";
https://www.ecma-international.org/ecma-262/6.0/#sec-imports-static-semantics-boundnames
しかし、次のコードはシンタックスエラーになる。as
によるエイリアスを使わない場合には、default
とfoo
は等価ではなくなる。
なぜならdefault
はECMAScriptの予約語であるからだ。
import { default, foo } from "other.js";
https://www.ecma-international.org/ecma-262/6.0/#sec-keywords
ここの肝は、Import構文のImportsListというもので、これはImportSpecifierのリストだが、ImportSpecifierはImportedBindingあるいはidentifierName as ImportedBinding
と定義されている。
https://www.ecma-international.org/ecma-262/6.0/#sec-imports
つまり、import { default }
と書いたときのdefault
はImportedBinding
として扱われるが、これはシンボルとして参照可能なので予約語のチェックに違反する。
一方で、import { default as alias }
と書いたときのdefault
はidentifierName
であって、ImportedBinding
ではなくなり、予約語のチェックから外れる。
結果的に、default as
はまるで普通のエイリアスされた名前付きインポートのように振る舞うことができる。
しかし仕様上はimport { default as ...}
構文というのは存在していないが、デフォルトエクスポートや予約語の仕様が絡んだ結果、事実上の構文っぽいものになっているのがややこしい。
MDNの構文例はexportとimportどちらも、デフォルトエクスポートがdefault
という名前付きエクスポートとして振る舞っている例を扱っていないが、
これは仕様が複雑で説明が難しいからされてないんだろうか。
とりあえず自分の中で整理がついたので良し。