Explain Codes LogoExplain Codes Logo

Typescript export vs. default export

javascript
typescript
export
import
Alex KataevbyAlex Kataev·Dec 4, 2024
TLDR

The named exports pattern allows you to export multiple values from a module and requires exact name matching on import. On the other hand, default exports enable you to export a single value which can be imported under any name of your choice.

Named export example:

// Export; pi is a mathematical constant not a delicious pastry export const pi = 3.14; export function calculateArea(radius) { return pi * radius * radius; } // Import import { pi, calculateArea } from './mathUtils';

Default export example:

// Export; this pi is still not a pastry const pi = 3.14; export default pi; // Import import PInotPastry from './mathUtils';

Choose named exports for clarity and multiple values; use default exports for a module's central export.

A practical guide to TypeScript Exports

While programming in TypeScript, the design of your code should aim to be scalable and maintainable for future use. Named exports play an integral part in that, providing a seamless refactoring experience. So if you need to change the export's name or divide it into smaller exports, named exports will ensure that consumer's code remains unaffected.

However, default exports are not to be overlooked, especially when it's the core exported API. In such case, using default exports simplifies import statements for common usage. Be aware though! Balance your use of default exports, as they may pose refactoring and readability challenges.

An Ace up your sleeve: Refactoring with Named Exports

When we talk about refactoring advantages with named exports, this is not just a theory, it's backed up with practical benefits:

  • Named exports can be grouped together when imported, fostering readability.
  • Your IDE's autocomplete support will love them.
  • Maintainability becomes easier when you know exactly where throughout the codebase your exports are used.

Know when to use default exports

You might want to keep default exports in mind in the following scenarios:

  • A module/method is the primary or only export of the file.
  • When you're designing a library, the default export tends to act as a public API.

Class and Component exports:

// Named export for a class export class MyClass {} // Default export for a class, but only if it's the headline act of the module export default class MainAttractionClass {}

Getting Imports right

Differentiating between import syntax is crucial:

  • Named import: import { myFunc } from 'myModule';
  • Default import: import myFunc from 'myModule';

Further methods for importing include:

  • Importing a whole module for side effects: import 'myModule';
  • Aliasing imports: import { myFunc as newFuncAlias } from 'myModule';

Dealing with common misunderstandings and pitfalls

While default export may seem simpler, saving you from the curly braces grind, it is not always the knight in shining armor. As pointed out by Basarat Ali Syed, the biggest problem arises when undergoing refactoring. Default exports can easily mask the true entity being exported, resulting in an ambiguous import where the module consumers are oblivious to the module’s imports or contents.

Potential challenges with default exports:

  • For developers to know what's available to import, they might need to look up the source code or refer to the module documentation.
  • Auto-import tools in some editors might not get it right all the time.
  • Searchability becomes a concern, as the exported entity might get imported under different names across various files.

On the contrary, named exports lay out an explicit list of what's being exported, making it self-documenting.

Maintainability Matters: Named Exports for Internal Code

Named exports tremendously help when you are dealing with a multitude of functions, constants, and classes especially for internal code base. They help avoid naming collisions and provide a clearer picture of what capabilities a module offers:

// Named export of functions and classes export const UTIL_CONST = 'ohSoConstant'; export class UtilClass {} // Who knew utility classes could be fun? export function utilFunction() {} // Utility belt packed!

Troubleshooting Export Problems

Have you stumbled on the error TS1192?

If it crops up, it means you are trying to use import on a non-default export without curly braces or on a default export with braces:

// Non-default export used as default import myFunction from 'myModule'; // Error if myFunction is not exported as default // Default export used with curly braces import { myDefaultFunc } from 'myModule'; // Error if myDefaultFunc is a default export

The fix is simple: Always verify the type of export with the import syntax. A quick look at the module file will let you know whether it's a named export or a default export.

What's up with Classes and Refactoring?

As suggested by Basarat Ali Syed, consider avoiding default exports for classes. With named exports, classes are explicitly required and can be renamed upon import, promoting explicit dependencies.

Perfecting Import and Export Patterns

TypeScript also supports several advanced module techniques:

  • Re-exporting: export { myFunction } from 'myModule';
  • Default export as function, classes, or objects: export default (() => {}) or export default class {}

Ensure that your choice of export type aligns with your project's architecture and design philosophy.