Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript export vs. default export

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.

like image 793
fos.alex Avatar asked Oct 23 '15 15:10

fos.alex


People also ask

What is the difference between export default and export?

Exports without a default tag are Named exports. Exports with the default tag are Default exports. Using one over the other can have effects on your code readability, file structure, and component organization. Named and Default exports are not React-centric ideas.

What is a default export TypeScript?

Default exports are meant to act as a replacement for this behavior; however, the two are incompatible. TypeScript supports export = to model the traditional CommonJS and AMD workflow. The export = syntax specifies a single object that is exported from the module.

Why you shouldn't use default exports?

Refactoring. Default exports make large-scale refactoring impossible since each importing site can name default import differently (including typos). On the contrary, named exports make such refactoring trivial.


2 Answers

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 
like image 111
David Sherret Avatar answered Sep 29 '22 16:09

David Sherret


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

like image 43
Hilton Fernandes Avatar answered Sep 29 '22 17:09

Hilton Fernandes