iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
👀

Default Export is Not That Bad

に公開

It seems quite a few people avoid using default exports in JavaScript/TypeScript, and I used to avoid them too, thinking "it's better to use named exports."
However, recently I've come to think that "it's perfectly fine to use default exports."

I'll write some casual thoughts about that.

VSCode's auto import

Items exported as default are subject to auto import in VSCode.
I'm not sure if it has always been this way for years, and the behavior has likely improved over time, but at least for now, there don't seem to be any major issues.

Basic behavior

As shown below, something exported as default in a file named foo.ts can be auto-imported with the name foo.
This also applies to cases where the file name is foo/index.ts or the extension is .tsx.

src/foo.ts
export default 'value'
src/index.ts
console.log(foo /* ← Auto import is possible here */)

In the case of named ones

I'll refer to cases where an expression is directly default-exported (excluding expressions consisting only of a variable) as anonymous default export, as shown previously.

On the other hand, I'll refer to the following cases as non-anonymous default export.
(You could also call it "named default export," but "non-anonymous" seems better to avoid confusion with "named export.")

// Named function declaration (Name: foo)
export default function foo() { }

// Named class declaration (Name: Foo)
export default class Foo { }

// Variable only (Name: value)
export default value

// Bonus: Variable only (Name: value)
export { value as default }

All patterns other than those listed above are anonymous default exports.

For non-anonymous default exports, in addition to the name based on the file name as mentioned earlier, it's also possible to auto-import using the name of the exported variable/function itself.

Renaming

When you rename a non-anonymously default-exported variable or function in VSCode, the locations where it's imported under the same name are automatically updated. This is very convenient.

References

In VSCode, you can also perform operations like "Go to References" or "Find All References" for default-exported variables and functions.

For anonymous cases, you Command+Click (or right-click and select from the menu) the default keyword.
For non-anonymous cases, you do the same on the variable or function name.

Prefer non-anonymous over anonymous default exports

I defined anonymous and non-anonymous default exports above.
When using default exports, I think it's better to use non-anonymous ones whenever possible.

Reasons:

  • Because you can auto-import with the intended name
    • If you use anonymous default exports, changing FooBar.ts to Foo/Bar.ts changes the name used for auto-import.
  • Because renaming updates the names on the import side.
  • For functions and classes, since they have intended names, it's easier to check them in stack traces or tools like React DevTools.

Finally, I'll talk about checking for anonymous default exports with ESLint.

Summary

  • Even when using default exports, you can still comfortably use VSCode features like auto-import.
  • There are two types of default exports: anonymous and non-anonymous.
  • Non-anonymous default exports are recommended.

That's all. Thank you for reading.


Bonus: Checking anonymous default exports with ESLint

ESLint has a rule called no-restricted-exports.
It allows you to prohibit specific exports or default exports, and I submitted a PR to add a rule to prohibit anonymous default exports there.

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

However, while not in ESLint core, there was a plugin that performs a similar check (how frustrating!).
It's eslint-plugin-import.
You can configure it as follows:

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

Discussion