👀

default exportはそこまで悪者でもないよ

2023/05/17に公開

JavaScript/TypeScriptにおけるdefault exportは使わないようにしている人が少なくないようですし、僕も「named exportを使った方が良いんだ」と思って避けていました。
しかし、最近は「default exportを使っても別に良い」と考えるようになりました。

その辺の話について、雑に書いてみます。

VSCodeのauto import

default exportされたものは、VSCodeでauto importの対象になります。
何年も前からそうだったかは不明ですし、挙動も少しずつ改善されてきたのでしょうが、少なくとも現時点では大きな問題はなさそうです。

基本の動作

次のように、foo.tsという名前のファイルでdefault exportされたものは、fooという名前でauto import可能です。
また、foo/index.tsのようなファイル名や拡張子が.tsxなどの場合も同様です。

src/foo.ts
export default 'value'
src/index.ts
console.log(foo /* ←ここでauto import可能 */)

名前付きの場合

先ほどのように式を直接default exportする場合を、匿名(anonymous) default exportと呼ぶことにします。(変数だけの式は除く)

それに対して、次のような場合を非匿名(non-anonymous) default exportと呼ぶことにします。
(名前付き(named) default exportと呼んでも良いですが、named exportと混同しそうなのでnon-anonymousが良さそう)

// 名前のある関数宣言 (名前: foo)
export default function foo() { }

// 名前のあるクラス宣言 (名前: Foo)
export default class Foo { }

// 変数だけ (名前: value)
export default value

// おまけ:変数だけ (名前: value)
export { value as default }

上に挙げたパターン以外は全て匿名default exportです。

非匿名default exportされたものは、上に書いたようにファイル名を基にした名前の外に、exportされた変数/関数などの名前でもauto importが可能です。

リネーム

VSCodeで非匿名default exportした変数/関数などをリネームすると、同じ名前でimportしている箇所が自動的に変更されます。とても便利。

参照

VSCodeで、default exportされた変数/関数などに対しても、Go references/Find all referencesなどの操作を行うことができます。

匿名の場合はdefaultキーワードをCommand+クリック、または右クリックしてメニューから選択します。
非匿名の場合は、変数/関数名に対して同様のことを行います。

匿名より非匿名のdefault exportを

上で、匿名/非匿名default exportを定義しました。
default exportを使う場合は、可能なら非匿名default exportを使うのが良いと思いました。

理由:

  • 意図した名前でauto importできるから
    • 匿名default exportを使っていると、FooBar.tsFoo/Bar.tsに変更するとauto importするための名前が変わってしまう
  • リネームするとimport側の名前を変更できるから
  • 関数/クラスの場合、意図した名前が付くのでスタックトレースやReact dev toolなどで確認しやすくなるから

ESLintで匿名default exportをチェックする話を最後に書きます。

まとめ

  • default exportを使っても、VSCodeのauto importなどの機能を快適に利用できる
  • 同じdefault exportでも、匿名と非匿名の2種類がある
  • 非匿名default exportがおすすめ

以上です。お読みいただきありがとうございました。


おまけ: ESLintで匿名default exportをチェックしたい

ESLintにno-restricted-exportsというルールがあります。
特定の名前のexportやdefault exportを禁止できるのですが、そこに匿名default exportを禁止するルールを追加するPRを出してみました。

https://github.com/eslint/eslint/pull/17141

しかし、ESLint本体ではないですが、同じようなチェックを行えるプラグインがありました。(悔しい)
eslint-plugin-importです。
次のように設定します。

eslintrc.json
{
  "plugins": ["import"],
  "rules": {
    "import/no-anonymous-default-export": ["error", {
      "allowCallExpression": false
    }]
  }
}

Discussion