`export const` vs. `export default` in ES6 `export const` vs. `export default` in ES6 javascript javascript

`export const` vs. `export default` in ES6


It's a named export vs a default export. export const is a named export that exports a const declaration or declarations.

To emphasize: what matters here is the export keyword as const is used to declare a const declaration or declarations. export may also be applied to other declarations such as class or function declarations.

Default Export (export default)

You can have one default export per file. When you import you have to specify a name and import like so:

import MyDefaultExport from "./MyFileWithADefaultExport";

You can give this any name you like.

Named Export (export)

With named exports, you can have multiple named exports per file. Then import the specific exports you want surrounded in braces:

// ex. importing multiple exports:import { MyClass, MyOtherClass } from "./MyClass";// ex. giving a named import a different name by using "as":import { MyClass2 as MyClass2Alias } from "./MyClass2";// use MyClass, MyOtherClass, and MyClass2Alias here

Or it's possible to use a default along with named imports in the same statement:

import MyDefaultExport, { MyClass, MyOtherClass} from "./MyClass";

Namespace Import

It's also possible to import everything from the file on an object:

import * as MyClasses from "./MyClass";// use MyClasses.MyClass, MyClasses.MyOtherClass and MyClasses.default here

Notes

  • The syntax favours default exports as slightly more concise because their use case is more common (See the discussion here).
  • A default export is actually a named export with the name default so you are able to import it with a named import:

    import { default as MyDefaultExport } from "./MyFileWithADefaultExport";


export default affects the syntax when importing the exported "thing", when allowing to import, whatever has been exported, by choosing the name in the import itself, no matter what was the name when it was exported, simply because it's marked as the "default".

A useful use case, which I like (and use), is allowing to export an anonymous function without explicitly having to name it, and only when that function is imported, it must be given a name:


Example:

Export 2 functions, one is default:

export function divide( x ){    return x / 2;}// only one 'default' function may be exported and the rest (above) must be namedexport default function( x ){  // <---- declared as a default function    return x * x;}

Import the above functions. Making up a name for the default one:

// The default function should be the first to import (and named whatever)import square, {divide} from './module_1.js'; // I named the default "square" console.log( square(2), divide(2) ); // 4, 1

When the {} syntax is used to import a function (or variable) it means that whatever is imported was already named when exported, so one must import it by the exact same name, or else the import wouldn't work.


Erroneous Examples:

  1. The default function must be first to import

    import {divide}, square from './module_1.js
  2. divide_1 was not exported in module_1.js, thus nothing will be imported

    import {divide_1} from './module_1.js
  3. square was not exported in module_1.js, because {} tells the engine to explicitly search for named exports only.

    import {square} from './module_1.js


Minor note: Please consider that when you import from a default export, the naming is completely independent. This actually has an impact on refactorings.

Let's say you have a class Foo like this with a corresponding import:

export default class Foo { }// The name 'Foo' could be anything, since it's just an// Identifier for the default exportimport Foo from './Foo'

Now if you refactor your Foo class to be Bar and also rename the file, most IDEs will NOT touch your import. So you will end up with this:

export default class Bar { }// The name 'Foo' could be anything, since it's just an// Identifier for the default export.import Foo from './Bar'

Especially in TypeScript, I really appreciate named exports and the more reliable refactoring. The difference is just the lack of the default keyword and the curly braces. This btw also prevents you from making a typo in your import since you have type checking now.

export class Foo { }//'Foo' needs to be the class name. The import will be refactored//in case of a rename!import { Foo } from './Foo'