Related
I have referred all the questions in stackoverflow.
But none of the suggested why and when to use default export.
I just saw that default can be metioned "When there is only one export in a file"
Any other reason for using default export in es6 modules?
Some differences that might make you choose one over the other:
Named Exports
Can export multiple values
MUST use the exported name when importing
Default Exports
Export a single value
Can use any name when importing
This article does a nice job of explaining when it would be a good idea to use one over the other.
It's somewhat a matter of opinion, but there are some objective aspects to it:
You can have only one default export in a module, whereas you can have as many named exports as you like.
If you provide a default export, the programmer using it has to come up with a name for it. This can lead to inconsistency in a codebase, where Mary does
import example from "./example";
...but Joe does
import ex from "./example";
In contrast, with a named export, the programmer doesn't have to think about what to call it unless there's a conflict with another identifier in their module.¹ It's just
import { example } from "./example";
With a named export, the person importing it has to specify the name of what they're importing. They get a nice early error if they try to import something that doesn't exist.
If you consistently only use named exports, programmers importing from modules in the project don't have to think about whether what they want is the default or a named export.
¹ If there is a conflict (for instance, you want example from two different modules), you can use as to rename:
import { example as widgetExample } from "./widget/example";
import { example as gadgetExample } from "./gadget/example";
You should almost always favour named exports, default exports have many downsides
Problems with default exports:
Difficult to refactor or ensure consistency since they can be named anything in the codebase other than what its actually called
Difficult to analyze by automated tools or provide code intellisense and autocompletion
They break tree shaking as instead of importing the single function you want to use you're forcing webpack to import the entire file with whatever other dead code it has leading to bigger bundle sizes
You can't export more than a single export per file
You lose faster/direct access to imports
checkout these articles for a more detailed explanation:
https://blog.neufund.org/why-we-have-banned-default-exports-and-you-should-do-the-same-d51fdc2cf2ad
https://humanwhocodes.com/blog/2019/01/stop-using-default-exports-javascript-module/
https://rajeshnaroth.medium.com/avoid-es6-default-exports-a24142978a7a
With named exports, one can have multiple named exports per file. Then import the specific exports they want surrounded in braces. The name of imported module has to be the same as the name of the exported module.
// imports
// ex. importing a single named export
import { MyComponent } from "./MyComponent";
// ex. importing multiple named exports
import { MyComponent, MyComponent2 } from "./MyComponent";
// ex. giving a named import a different name by using "as":
import { MyComponent2 as MyNewComponent } from "./MyComponent";
// exports from ./MyComponent.js file
export const MyComponent = () => {}
export const MyComponent2 = () => {}
You can also alias named imports, assign a new name to a named export as you import it, allowing you to resolve naming collisions, or give the export a more informative name.
import MyComponent as MainComponent from "./MyComponent";
You can also Import all the named exports onto an object:
import * as MainComponents from "./MyComponent";
// use MainComponents.MyComponent and MainComponents.MyComponent2 here
One can have only one default export per file. When we import we have to specify a name and import like:
// import
import MyDefaultComponent from "./MyDefaultExport";
// export
const MyComponent = () => {}
export default MyComponent;
The naming of import is completely independent in default export and we can use any name we like.
From MDN:
Named exports are useful to export several values. During the import, one will be able to use the same name to refer to the corresponding value.
Concerning the default export, there is only a single default export per module. A default export can be a function, a class, an object or anything else. This value is to be considered as the “main” exported value since it will be the simplest to import.
There aren't any definitive rules, but there are some conventions that people use to make it easier to structure or share code.
When there is only one export in the entire file, there is no reason to make it named.
Also, when your module has one main purpose, it could make sense to make that your default export. In those cases you can extra named exports
In react for example, React is the default export, since that is often the only part that you need. You don't always Component, so that's a named export that you can import when needed.
import React, {Component} from 'react';
In the other cases where one module has multiple equal (or mostly equal) exports, it's better to use named exports
import { blue, red, green } from 'colors';
1st Method:-
export foo; //so that this can be used in other file
import {foo} from 'abc'; //importing data/fun from module
2nd Method:-
export default foo; //used in one file
import foo from 'blah'; //importing data/fun from module
3rd Method:-
export = foo;
import * as foo from 'blah';
The above methods roughly compile to the following syntax below:-
//all export methods
exports.foo = foo; //1st method
exports['default'] = foo; //2nd method
module.exports = foo; //3rd method
//all import methods
var foo = require('abc').foo; //1st method
var foo = require('abc')['default']; //2nd method
var foo = require('abc'); //3rd method
For more information, visit to Default keyword explaination
Note:- There can be only one export default in one file.
So whenever we are exporting only 1 function, then it's better to use default keyword while exporting
EASIEST DEFINITION TO CLEAR CONFUSIONS
Let us understand the export methods, first, so that we can analyze ourselves when to use what, or why do we do what we do.
Named exports: One or more exports per module. When there are more than one exports in a module, each named export must be restructured while importing. Since there could be either export in the same module and the compiler will not know which one is required unless we mention it.
//Named export , exporting:
export const xyz = () =>{
}
// while importing this
import {xyx} from 'path'
or
const {xyz} = require(path)
The braces are just restructuring the export object.
On the other hand , default exports are only one export per module , so they are pretty plain.
//exporting default
const xyz =() >{
};
export default xyz
//Importing
import xyz from 'path'
or
const xyz = require(path)
I hope this was pretty simple to understand, and by now you can understand why you import React modules within braces...
Named Export: (export)
With named exports, one can have multiple named exports per file. Then import the specific exports they want surrounded in braces. The name of imported module has to be the same as the name of the exported module.
// imports
// ex. importing a single named export
import { MyComponent } from "./MyComponent";
// ex. importing multiple named exports
import { MyComponent, MyComponent2 } from "./MyComponent";
// ex. giving a named import a different name by using "as":
import { MyComponent2 as MyNewComponent } from "./MyComponent";
// exports from ./MyComponent.js file
export const MyComponent = () => {}
export const MyComponent2 = () => {}
Import all the named exports onto an object:
// use MainComponents.MyComponent and MainComponents.MyComponent2 here
import * as MainComponents from "./MyComponent";
Default Export: (export default)
One can have only one default export per file. When we import we have to specify a name and import like:
// import
import MyDefaultComponent from "./MyDefaultExport";
// export
const MyComponent = () => {}
export default MyComponent;
Note: The naming of import is completely independent in default export and we can use any name we like.
Here's a great answer that explains default and named imports in ES6
Problem
In React Native project in my company I came across such code, aggregating exports from multiple modules:
export Icon from "./Icon";
export Input from "./Input";
export Pills from "./Pills";
My editor highlights this as invalid syntax. I checked MDN docs on export and indeed they don't list such a syntax for aggregation. From what they list it seems the proper one would be:
export { default as Icon } from "./Icon";
export { default as Input } from "./Input";
export { default as Pills } from "./Pills";
But then the first code works in React Native project I'm in.
Question
Is this a valid syntax in JavaScript, or is it only available by some third party package we're using in the project?
You are right, but you are not really using ES6 module.
You are using babel, with the metro-react-native-babel-preset. Which make the above syntax valid.
As always, there's a proposal to make it part of the language, but it's currently on stage one.
From the proposal:
The proposed addition follows this same symmetric pattern:
Importing the "default" name (existing):
import v from "mod";
Exporting that name (existing):
import v from "mod"; export {v};
Symmetric "export from" (proposed):
export v from "mod";
In the context of ES6 and Javascript. Syntactically react native method would be not valid. However As the #federkun suggested, it is valid under the context of babel and on the same desk proposal is already made.
However, "default" is used to export default exports which can be exported again
export {default} from '.\example.js'
or you can use name export within curly braces to export only named export. Besides, to export all the named export you can use "*"
export * from '.\example.js'
export {test} from '.\example.js'
Or you can add babel dependency to use the same syntax.
Context
JavaScript has two types of exports: normal[1] and default.
EDIT: JavaScript has two types of export syntaxes
Normal exports
class Foo {...}
class Bar {...}
export {
Foo,
Bar,
};
or
export class Foo {...}
export class Bar {...}
Normal exports can be imported in two ways: namespace[1] imports and named imports (looks similar to destructuring).
Namespace imports
import * as Baz from './baz';
Named imports
import {Foo, Bar} from './baz';
Default exports
class Foo {...}
class Bar {...}
export default {
Foo,
Bar,
};
Default exports can also be imported in two ways: namespace imports and named imports (in a hackish way using destructuring in a separate statement)
Namespace imports
import Baz from './baz';
Named imports
import temp_Baz from './baz';
const {Foo, Bar} = temp_Baz;
Question
Both normal exports and default exports have the same functionality - they can be imported into a namespace, and they can be destructured into smaller pieces.
1) What are the reasons JavaScript has default exports, instead of sticking with just normal exports and having the import syntax be the following?
import <varName> from <location>;
<varName> would allow destructuring like any variable assignment, without a special "named" import.
Node.js managed without default exports, and the only additional change would be to allow exporting of a single value:
module.exports = class Foo {...}
This could be done with export = or export only or something similar:
export only class Foo {...}
So now you might ask, what is the difference between export only and export default?
export only exports could be imported with the same syntax, whereas export default requires a different importing syntax. To allow both syntaxes to work for the module user, the module must both export and export default the same items (which is something I do in all my modules).
export default is renamed to export only which is a better term in my opinion (less confusing; clearer)
2) All the differences listed above are pros. Are there any other differences that are cons? Or can any of the above differences also be cons?
Edit
It seems I misunderstood the intended use for export default.
It's for adding a default export on top of the regular exports.
So I'd now like to know when are default exports used? Although I probably shouldn't add more to this question.
If the only use for default exports is if your module only has a single item to export, then this question still applies.
Edit 2
Now it seems that the intended use is if a module only exports a single item. So my question still applies. Why not replace default exports with export only, removing the need for an additional default import syntax?
Notes
[1] I am not sure if this is the correct term to use
The existence of "default exports" as well as "named exports" is due to design by committee. This was convincingly argued by Andreas Rossberg during the original design discussions:
Some want modules in the conventional sense, as encapsulated namespaces with named exports, which you can import and access qualified or unqualified, and where imports are checked.
Some want modules in the specific pre-ES6 JavaScript style, where they can be any arbitrary JS value, and in the good old JavaScript tradition that checking doesn't matter.
The current design (including the newest suggestions for imports) seems to please neither side, because it tries to be the former semantically, but wants to optimise for the latter syntactically. The main outcome is confusion.
That is, the motivation for "default exports" was not technical, but political, designed to appease those in the CommonJS and AMD worlds, where a module exports a single value. This neatly explains why we have two module systems in one; something we don't see in other programming languages.
(Thanks a lot to Bergi, who found and cited this thread in his answer. However, I disagree with his conclusion that default exports are motivated by a need for a shorthand. I don't see much discussion of this in the original threads.)
JavaScript has two types of exports: normal and default.
No, not really. JavaScript has only one kind of export structure. It has different syntaxes though.
export default function x() {} is just a shorthand notation for function x(){}; export { x as default }.
import x from '…' is just a shorthand notation for import { default as x } from '…'.
The difference between your the two module exports you discussed is much bigger than the single default keyword. They only look so similar because you used shorthand notations. Fully spelled out, it's
export {
Foo as Foo,
Bar as Bar,
} // a declaration
vs
export default ({
Foo: Foo,
Bar: Bar,
}); // an object literal
Both normal exports and default exports have the same functionality - they can be imported into a namespace, and they can be destructured into smaller pieces.
No, they don't. Imports provide aliases for the exported variable declarations, there's no destructuring - and you cannot do that to properties of a default-exported object.
What are the reasons JavaScript has default exports, instead of sticking with just normal exports and having the import syntax be the following?
See https://esdiscuss.org/topic/moduleimport. The default-export syntax provides a shorthand syntax for exporting under the special name default (which is not a valid variable name otherwise), as it is a quite common use case to export only a single thing from a module. It doesn't require explicitly naming a value when there is only one in this module anyway. In this regard, it has very much the purpose you envisioned for your export only suggestion, but it is only one export not providing a full namespace of multiple aliasable exports.
export default {
Foo,
Bar,
}
I don't understand why you've demonstrated this structure. This isn't how it's supposed to be used.
The default export really be though of as just another export. If you import * as Package from "package" you'll realise... Package.default is the default export
The only change is the syntactic shortcut:
import alias from "package" = import {default as alias} from "package"
It makes consumption of many packages easier / simpler.
export = ... is not the same as export default ...
The prior returns a module structure of ... where as latter returns a module structure of {default: ...}
What is the difference in TypeScript between export and default export?
In all the tutorials, I see people exporting their classes and I cannot compile my code if I don't add the default keyword before exporting.
Also, I couldn't find any trace of the default export keyword in the official TypeScript documentation.
export class MyClass {
collection = [1,2,3];
}
Does not compile. But:
export default class MyClass {
collection = [1,2,3];
}
Does.
The error is:
error TS1192: Module '"src/app/MyClass"' has no default export.
Default Export (export default)
// MyClass.ts -- using default export
export default class MyClass { /* ... */ }
The main difference is that you can only have one default export per file and you import it like so:
import MyClass from "./MyClass";
You can give it any name you like. For example this works fine:
import MyClassAlias from "./MyClass";
Named Export (export)
// MyClass.ts -- using named exports
export class MyClass { /* ... */ }
export class MyOtherClass { /* ... */ }
When you use a named export, you can have multiple exports per file and you need to import the exports surrounded in braces:
import { MyClass } from "./MyClass";
Note: Adding the braces will fix the error you're describing in your question and the name specified in the braces needs to match the name of the export.
Or say your file exported multiple classes, then you could import both like so:
import { MyClass, MyOtherClass } from "./MyClass";
// use MyClass and MyOtherClass
Or you could give either of them a different name in this file:
import { MyClass, MyOtherClass as MyOtherClassAlias } from "./MyClass";
// use MyClass and MyOtherClassAlias
Or you could import everything that's exported by using * as:
import * as MyClasses from "./MyClass";
// use MyClasses.MyClass and MyClasses.MyOtherClass here
Which to use?
In ES6, default exports are concise because their use case is more common; however, when I am working on code internal to a project in TypeScript, I prefer to use named exports instead of default exports almost all the time because it works very well with code refactoring. For example, if you default export a class and rename that class, it will only rename the class in that file and not any of the other references in other files. With named exports it will rename the class and all the references to that class in all the other files.
It also plays very nicely with barrel files (files that use namespace exports—export *—to export other files). An example of this is shown in the "example" section of this answer.
Note that my opinion on using named exports even when there is only one export is contrary to the TypeScript Handbook—see the "Red Flags" section. I believe this recommendation only applies when you are creating an API for other people to use and the code is not internal to your project. When I'm designing an API for people to use, I'll use a default export so people can do import myLibraryDefaultExport from "my-library-name";. If you disagree with me about doing this, I would love to hear your reasoning.
That said, find what you prefer! You could use one, the other, or both at the same time.
Additional Points
A default export is actually a named export with the name default, so if the file has a default export then you can also import by doing:
import { default as MyClass } from "./MyClass";
And take note these other ways to import exist:
import MyDefaultExportedClass, { Class1, Class2 } from "./SomeFile";
import MyDefaultExportedClass, * as Classes from "./SomeFile";
import "./SomeFile"; // runs SomeFile.js without importing any exports
I was trying to solve the same problem, but found an interesting advice by Basarat Ali Syed, of TypeScript Deep Dive fame, that we should avoid the generic export default declaration for a class, and instead append the export tag to the class declaration. The imported class should be instead listed in the import command of the module.
That is: instead of
class Foo {
// ...
}
export default Foo;
and the simple import Foo from './foo'; in the module that will import, one should use
export class Foo {
// ...
}
and import {Foo} from './foo' in the importer.
The reason for that is difficulties in the refactoring of classes, and the added work for exportation. The original post by Basarat is in Avoid Export Default
Named export
In TypeScript you can export with the export keyword. It then can be imported via import {name} from "./mydir";. This is called a named export. A file can export multiple named exports. Also the names of the imports have to match the exports. For example:
// foo.js file
export class foo{}
export class bar{}
// main.js file in same dir
import {foo, bar} from "./foo";
The following alternative syntax is also valid:
// foo.js file
function foo() {};
function bar() {};
export {foo, bar};
// main.js file in same directory
import {foo, bar} from './foo'
Default export
We can also use a default export. There can only be one default export per file. When importing a default export we omit the square brackets in the import statement. We can also choose our own name for our import.
// foo.js file
export default class foo{}
// main.js file in same directory
import abc from "./foo";
It's just JavaScript
Modules and their associated keyword like import, export, and export default are JavaScript constructs, not TypeScript. However, TypeScript added the exporting and importing of interfaces and type aliases to it.
Here's an example with simple object exporting.
var MyScreen = {
/* ... */
width : function (percent){
return window.innerWidth / 100 * percent
}
height : function (percent){
return window.innerHeight / 100 * percent
}
};
export default MyScreen
In the main file (use it when you don't want and don't need to create a new instance) and it is not global, you will import this only when it is needed:
import MyScreen from "./module/screen";
console.log(MyScreen.width(100));
I have referred all the questions in stackoverflow.
But none of the suggested why and when to use default export.
I just saw that default can be metioned "When there is only one export in a file"
Any other reason for using default export in es6 modules?
Some differences that might make you choose one over the other:
Named Exports
Can export multiple values
MUST use the exported name when importing
Default Exports
Export a single value
Can use any name when importing
This article does a nice job of explaining when it would be a good idea to use one over the other.
It's somewhat a matter of opinion, but there are some objective aspects to it:
You can have only one default export in a module, whereas you can have as many named exports as you like.
If you provide a default export, the programmer using it has to come up with a name for it. This can lead to inconsistency in a codebase, where Mary does
import example from "./example";
...but Joe does
import ex from "./example";
In contrast, with a named export, the programmer doesn't have to think about what to call it unless there's a conflict with another identifier in their module.¹ It's just
import { example } from "./example";
With a named export, the person importing it has to specify the name of what they're importing. They get a nice early error if they try to import something that doesn't exist.
If you consistently only use named exports, programmers importing from modules in the project don't have to think about whether what they want is the default or a named export.
¹ If there is a conflict (for instance, you want example from two different modules), you can use as to rename:
import { example as widgetExample } from "./widget/example";
import { example as gadgetExample } from "./gadget/example";
You should almost always favour named exports, default exports have many downsides
Problems with default exports:
Difficult to refactor or ensure consistency since they can be named anything in the codebase other than what its actually called
Difficult to analyze by automated tools or provide code intellisense and autocompletion
They break tree shaking as instead of importing the single function you want to use you're forcing webpack to import the entire file with whatever other dead code it has leading to bigger bundle sizes
You can't export more than a single export per file
You lose faster/direct access to imports
checkout these articles for a more detailed explanation:
https://blog.neufund.org/why-we-have-banned-default-exports-and-you-should-do-the-same-d51fdc2cf2ad
https://humanwhocodes.com/blog/2019/01/stop-using-default-exports-javascript-module/
https://rajeshnaroth.medium.com/avoid-es6-default-exports-a24142978a7a
With named exports, one can have multiple named exports per file. Then import the specific exports they want surrounded in braces. The name of imported module has to be the same as the name of the exported module.
// imports
// ex. importing a single named export
import { MyComponent } from "./MyComponent";
// ex. importing multiple named exports
import { MyComponent, MyComponent2 } from "./MyComponent";
// ex. giving a named import a different name by using "as":
import { MyComponent2 as MyNewComponent } from "./MyComponent";
// exports from ./MyComponent.js file
export const MyComponent = () => {}
export const MyComponent2 = () => {}
You can also alias named imports, assign a new name to a named export as you import it, allowing you to resolve naming collisions, or give the export a more informative name.
import MyComponent as MainComponent from "./MyComponent";
You can also Import all the named exports onto an object:
import * as MainComponents from "./MyComponent";
// use MainComponents.MyComponent and MainComponents.MyComponent2 here
One can have only one default export per file. When we import we have to specify a name and import like:
// import
import MyDefaultComponent from "./MyDefaultExport";
// export
const MyComponent = () => {}
export default MyComponent;
The naming of import is completely independent in default export and we can use any name we like.
From MDN:
Named exports are useful to export several values. During the import, one will be able to use the same name to refer to the corresponding value.
Concerning the default export, there is only a single default export per module. A default export can be a function, a class, an object or anything else. This value is to be considered as the “main” exported value since it will be the simplest to import.
There aren't any definitive rules, but there are some conventions that people use to make it easier to structure or share code.
When there is only one export in the entire file, there is no reason to make it named.
Also, when your module has one main purpose, it could make sense to make that your default export. In those cases you can extra named exports
In react for example, React is the default export, since that is often the only part that you need. You don't always Component, so that's a named export that you can import when needed.
import React, {Component} from 'react';
In the other cases where one module has multiple equal (or mostly equal) exports, it's better to use named exports
import { blue, red, green } from 'colors';
1st Method:-
export foo; //so that this can be used in other file
import {foo} from 'abc'; //importing data/fun from module
2nd Method:-
export default foo; //used in one file
import foo from 'blah'; //importing data/fun from module
3rd Method:-
export = foo;
import * as foo from 'blah';
The above methods roughly compile to the following syntax below:-
//all export methods
exports.foo = foo; //1st method
exports['default'] = foo; //2nd method
module.exports = foo; //3rd method
//all import methods
var foo = require('abc').foo; //1st method
var foo = require('abc')['default']; //2nd method
var foo = require('abc'); //3rd method
For more information, visit to Default keyword explaination
Note:- There can be only one export default in one file.
So whenever we are exporting only 1 function, then it's better to use default keyword while exporting
EASIEST DEFINITION TO CLEAR CONFUSIONS
Let us understand the export methods, first, so that we can analyze ourselves when to use what, or why do we do what we do.
Named exports: One or more exports per module. When there are more than one exports in a module, each named export must be restructured while importing. Since there could be either export in the same module and the compiler will not know which one is required unless we mention it.
//Named export , exporting:
export const xyz = () =>{
}
// while importing this
import {xyx} from 'path'
or
const {xyz} = require(path)
The braces are just restructuring the export object.
On the other hand , default exports are only one export per module , so they are pretty plain.
//exporting default
const xyz =() >{
};
export default xyz
//Importing
import xyz from 'path'
or
const xyz = require(path)
I hope this was pretty simple to understand, and by now you can understand why you import React modules within braces...
Named Export: (export)
With named exports, one can have multiple named exports per file. Then import the specific exports they want surrounded in braces. The name of imported module has to be the same as the name of the exported module.
// imports
// ex. importing a single named export
import { MyComponent } from "./MyComponent";
// ex. importing multiple named exports
import { MyComponent, MyComponent2 } from "./MyComponent";
// ex. giving a named import a different name by using "as":
import { MyComponent2 as MyNewComponent } from "./MyComponent";
// exports from ./MyComponent.js file
export const MyComponent = () => {}
export const MyComponent2 = () => {}
Import all the named exports onto an object:
// use MainComponents.MyComponent and MainComponents.MyComponent2 here
import * as MainComponents from "./MyComponent";
Default Export: (export default)
One can have only one default export per file. When we import we have to specify a name and import like:
// import
import MyDefaultComponent from "./MyDefaultExport";
// export
const MyComponent = () => {}
export default MyComponent;
Note: The naming of import is completely independent in default export and we can use any name we like.
Here's a great answer that explains default and named imports in ES6