ESMエクスポート:名前付き vs デフォルト?
名前をつけるか、つけないか?
JavaScriptでnamedエクスポートとdefaultエクスポート、どちらを使うべきか?
このトピックについて、強い言葉で書かれた記事に事欠くことはない。
大多数はdefault exportを「ひどい」と断じる。一方、defaultが勝つべきだと主張する人もいる(Airbnbスタイルガイドなど)。
彼らが問題視するのは、完全に一時的なことだ:IDEの自動インポートバグ、特定のバンドラーのツリーシェーキング能力、あるいはインポート命名時のタイポの可能性。
そもそもexportすることの本質を見落としていないか?
コードはコミュニケーションである。✨
importする側に対して、_ものの使い方_を示すシグナルを送っているのだ。
じゃあ、何を伝えているのか?
大まかに言えば、モダンJavaScriptでものをエクスポートする方法は2つある:
export defaultは「これが最も重要な単一のものだ」と堂々と宣言する。ついでに「名前付きエクスポートはあくまで脇役」とも伝える。named exportは「間違いなく一つのものだ!」と言う。いくつかの疑問も浮かぶ。「他に仲間いる?」「そいつらは招待されてるの?それとも必須?」
もちろん両方を組み合わせたり、コードベースの異なる部分で異なるアプローチを使うこともできる。記事の最後でさらに例を紹介。
弱い引数だな、おい
よくある「一時的な問題」を片付けていこう。
- 引数 #1:名前付きエクスポートは名前の一貫性を保証する。source
- いや、保証しない。lintルールを探してるんじゃないのか?
- (残念なお知らせだが、変数が何をしでかせるか知るまでもない!)
// どちらもエイリアス可能!import { Knife as Handle } from "./knife.js"; // 🔪import { default as Handle } from "./knife.js"; // 🔪import Handle from "./knife.js"; // 🔪-
引数 #2:
import * as soManyKnives from './kinves.js'を使って名前付きエクスポートをまとめられる。(リンクなし、著者撤回済み。)- いい機能だ。でも本質じゃない。
- で、この仕掛けをどう使えばいいんだ?作者の意図がない。
-
引数 #3:名前付きエクスポートの方がIDEのインポートやリネームサポートが優れている。source
-
間違い(もう)。ツールを設定・更新しよう。
-
サポートはVS Code、IntelliJなどで3年以上前から存在している。
-
それでも、
default exportsで最高のIDE&リファクタリング体験を得るには、いくつかの「ベストプラクティス」がある。 -
✅
export default function UserService() {}- 常に名前付き関数を優先する。 -
❌
export default function() { }- 無名関数はファイル名に暗黙的に紐づかない。ものに名前をつけないと、コンピューターに変更を依頼するのが難しくなる。 -
**注:**歴史的な理由により、
export defaultとconst式を組み合わせることはできない。export default const Knife = () => {...blade, ...handle}// ^ ❌ サポートされていない ❌ ^// Cannot export default const ....// ==========================// ただし、一度宣言すればconst変数をデフォルトとしてエクスポートできる。const Knife = () => {...blade, ...handle}export default Knife;// ^ ✅ 有効// 完全を期すために:export default class anyoneStillUseThese {}// ^ ✅ クラスをデフォルトとしてエクスポートするのも有効
-
まとめ
ものをエクスポートする方法には実はたくさんの組み合わせがあり、それぞれが異なる物語を語る:
| デフォルト(エクスポート) | 名前付き(エクスポート) | プライベート関数 | パターン | 意味 |
|---|---|---|---|---|
| ✅ | ❌ | ❌ | デフォルトエクスポート1つ。 | 「単一の目的を持つ関数1つをお届け!」 |
| ❌ | ✅ | ❌ | 名前付きエクスポート1つ。 | 「リネームしないでください。」 |
| ✅ | ✅ | ✅ | デフォルトエクスポート + 複数のエクスポートされていない「プライベート」関数 | 「関連ロジックはこちら。ついでに、クラスっぽい動作を期待して。「 |
| ❌ | ❌ | ✅ | 複数の名前付きエクスポート、一般的なファイル名。 | 「緩く関連したものたちの詰め合わせ。階層関係は暗示しない。」 |
| ✅ | ✅ | ❌ | 単一の名前付きエクスポートをデフォルトとしてもエクスポート。 | 「インポートでしくじることはない。」 |
**考えてみてほしい:**ファイル名がそのエクスポートの一つと一致する場合、一致しない場合、何を伝えているのだろうか?(例えば、多くの関数を持つutils.jsなど。)
結論
コードがコミュニケーションであるなら、どうかexportは本気でやってほしい。💞