330
votes

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.

4
Some light reading on the topic. It might help if you show how you're importing this class, I believe that's where the error is occurring (you probably need to alter the import syntax to fix the error scenario).Sunil D.
"export" and "export default" are not TypeScript at all - they're ES6.Sensei James

4 Answers

537
votes

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
13
votes

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 export default can lead to problems

5
votes

Named export

In TS 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 dir
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.

1
votes

Here's 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 main file (Use when you don't want and don't need to create new instance) and it is not global you will import this only when it needed :

import MyScreen from "./module/screen";
console.log( MyScreen.width(100) );