Typescript: Write a FAQ entry for `export =` vs `export default` / `import ` variants

Created on 22 Feb 2016  路  12Comments  路  Source: microsoft/TypeScript

People don't understand the difference between these things:

export default class Foo {}
/* or */
class Foo {}
export = Foo;
/* or */
export class Foo { }

People also don't understand the difference between these things:

import x = require('y');
import x from 'y';
import { x } from 'y'
import * as x from 'y';

We need to write a comprehensive answer that explains which import statements correctly acquire which exports, and also describe auto-lifting behavior present in some loaders.

Docs

Most helpful comment

export default ... (Default Export)

// calculator.ts                                // compiled.js
// =============                                // ===========
export default class Calculator {               // var Calculator = /** @class */ (function () {
    public add(num1, num2) {                    //     function Calculator() {}
        return num1 + num2;                     //     Calculator.prototype.add = function (num1, num2) {
    }                                           //         return num1 + num2;
}                                               //     };
                                                //     return Calculator;
                                                // }());
                                                // exports["default"] = Calculator;

import ... from "module";

// importer.ts                                  // compiled.js
// ===========                                  // ===========
import Calculator from "./calculator";          // exports.__esModule = true;
                                                // var calculator = require("./calculator");
let calc = new Calculator();                    // var calc = new calculator["default"]();
                                                // console.log(calc.add(2, 2));
console.log(calc.add(2, 2));                    //
Notes:
  • A default export can be imported with any name.
  • Functionally equivalent to import * as Calculator from "./calculator"; and then instantiating it using new Calculator.default().

export = ...

// calculator.ts                                // compiled.js
// =============                                // ===========
export = class Calculator {                     // module.exports = /** @class */ (function () {
    public add(num1, num2) {                    //     function Calculator() {}
        return num1 + num2;                     //     Calculator.prototype.add = function (num1, num2) {
    }                                           //         return num1 + num2;
}                                               //     };
                                                //     return Calculator;
                                                // }());

import ... = require("module");

// importer.ts                                  // compiled.js
// ===========                                  // ===========
import Calculator = require("./calculator");    // exports.__esModule = true;
                                                // var Calculator = require("./calculator");
let calc = new Calculator();                    // var calc = new Calculator();
                                                // console.log(calc.add(2, 2));
console.log(calc.add(2, 2));                    //
Notes:
  • This syntax is only used when importing a CommonJS module.

export ... (Named Export)

// calculator.ts                                // compiled.js
// =============                                // ===========
export class Calculator {                       // exports.__esModule = true;
    public add(num1, num2) {                    // var Calculator = /** @class */ (function () {
        return num1 + num2;                     //     function Calculator() {}
    }                                           //     Calculator.prototype.add = function (num1, num2) {
}                                               //         return num1 + num2;
                                                //     };
                                                //     return Calculator;
                                                // }());
                                                // exports.Calculator = Calculator;

import { ... } from "module";

// importer.ts                                  // compiled.js
// ===========                                  // ===========
import { Calculator } from "./calculator";      // exports.__esModule = true;
                                                // var calculator = require("./calculator");
let calc = new Calculator();                    // var calc = new calculator.Calculator();
                                                // console.log(calc.add(2, 2));
console.log(calc.add(2, 2));                    //
Notes:
  • Named exports are useful to export several values.
  • During the import, you must use the same name of the corresponding object.

All 12 comments

I've actually been trying to write this up today as part of fixing up the module bugs assigned to me. I could extract out the general info from the internal info as the basis.

Maybe I'll regret this... but feel free to assign to me if someone is not already working on it.

We should put any additional information for this in the handbook module page: https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Modules.md

we can also add a link to that page in the FAQ page.

Looks good! A couple of things that would be really useful additions:

  • Some of the config/path work for modules that @vladima did. It'd be useful to add that here (when it ships I guess).
  • Clarify interop (e.g. working with existing modules written in a CommonJS style - for example, I'm pretty sure this statement in there is wrong: _"When importing a module using export =, TypeScript-specific import let = require("module") must be used to import the module."_).
  • Are there any consideration for interop with Babel or SystemJS (e.g. the impact of the __esModule property and hoisting of the module.exports to the default property by some loaders, and our allowSyntheticDefaultImports flag).
  • Recently added _augmentation_ for modules.
  • Perhaps some examples of a project configuration that works at runtime (I see more folks struggle here than with getting compilation to work - especially with loaders like SystemJS).

I do not know, who is responsible for the handbook on typescriptlang.org, but the chapter "Going external" should also cover this topic, or at least a hint:
http://www.typescriptlang.org/Handbook#modules-going-external

I'd add export as namespace Foo to this list.

+1 pls. I dont even know the answer now that finding this issue :/

TL;DR: export = or import = require implies the module was written as CommonJS, export default implies it's been authored as an ECMAScript module.

export = and import x = require('./x') corresponds to CommonJS/AMD/etc.'s notion of module.exports:

// ./a.js
module.exports = { a: 10, b: 20 };

// ./b.js
let a = require('./a');

A lot of the time, people will have exactly one thing that they're exporting, like a function:

// ./a.js
module.exports = function foo() { /*...*/ }

// ./b.js
var a = require('./a');
a();

export default is a construct in ES2015 modules that is supposed to give an easy way to say "hey, here's the main thing you import from this module". ES2015 gives it a special syntax.

// a.js
export default function foo() {
    // ...
}

// b.js
import a from './a.js';
a();

But it's just special syntax; really, default is like any member on an ES2015 module record. b.js could have been written like the following:

import * as a from './a.js';
a.default();

import { default as aFujnc } from './a.js'
aFunc();

export default ... (Default Export)

// calculator.ts                                // compiled.js
// =============                                // ===========
export default class Calculator {               // var Calculator = /** @class */ (function () {
    public add(num1, num2) {                    //     function Calculator() {}
        return num1 + num2;                     //     Calculator.prototype.add = function (num1, num2) {
    }                                           //         return num1 + num2;
}                                               //     };
                                                //     return Calculator;
                                                // }());
                                                // exports["default"] = Calculator;

import ... from "module";

// importer.ts                                  // compiled.js
// ===========                                  // ===========
import Calculator from "./calculator";          // exports.__esModule = true;
                                                // var calculator = require("./calculator");
let calc = new Calculator();                    // var calc = new calculator["default"]();
                                                // console.log(calc.add(2, 2));
console.log(calc.add(2, 2));                    //
Notes:
  • A default export can be imported with any name.
  • Functionally equivalent to import * as Calculator from "./calculator"; and then instantiating it using new Calculator.default().

export = ...

// calculator.ts                                // compiled.js
// =============                                // ===========
export = class Calculator {                     // module.exports = /** @class */ (function () {
    public add(num1, num2) {                    //     function Calculator() {}
        return num1 + num2;                     //     Calculator.prototype.add = function (num1, num2) {
    }                                           //         return num1 + num2;
}                                               //     };
                                                //     return Calculator;
                                                // }());

import ... = require("module");

// importer.ts                                  // compiled.js
// ===========                                  // ===========
import Calculator = require("./calculator");    // exports.__esModule = true;
                                                // var Calculator = require("./calculator");
let calc = new Calculator();                    // var calc = new Calculator();
                                                // console.log(calc.add(2, 2));
console.log(calc.add(2, 2));                    //
Notes:
  • This syntax is only used when importing a CommonJS module.

export ... (Named Export)

// calculator.ts                                // compiled.js
// =============                                // ===========
export class Calculator {                       // exports.__esModule = true;
    public add(num1, num2) {                    // var Calculator = /** @class */ (function () {
        return num1 + num2;                     //     function Calculator() {}
    }                                           //     Calculator.prototype.add = function (num1, num2) {
}                                               //         return num1 + num2;
                                                //     };
                                                //     return Calculator;
                                                // }());
                                                // exports.Calculator = Calculator;

import { ... } from "module";

// importer.ts                                  // compiled.js
// ===========                                  // ===========
import { Calculator } from "./calculator";      // exports.__esModule = true;
                                                // var calculator = require("./calculator");
let calc = new Calculator();                    // var calc = new calculator.Calculator();
                                                // console.log(calc.add(2, 2));
console.log(calc.add(2, 2));                    //
Notes:
  • Named exports are useful to export several values.
  • During the import, you must use the same name of the corresponding object.

export default ... (Default Export)

// calculator.ts                                // compiled.js
// =============                                // ===========
export default class Calculator {               // var Calculator = /** @class */ (function () {
    public add(num1, num2) {                    //     function Calculator() {}
        return num1 + num2;                     //     Calculator.prototype.add = function (num1, num2) {
    }                                           //         return num1 + num2;
}                                               //     };
                                                //     return Calculator;
                                                // }());
                                                // exports["default"] = Calculator;

import ... from "module";

// importer.ts                                  // compiled.js
// ===========                                  // ===========
import Calculator from "./calculator";          // exports.__esModule = true;
                                                // var calculator = require("./calculator");
let calc = new Calculator();                    // var calc = new calculator["default"]();
                                                // console.log(calc.add(2, 2));
console.log(calc.add(2, 2));                    //
Notes:
  • A default export can be imported with any name.
  • Functionally equivalent to import * as Calculator from "./calculator"; and then instantiating it using new Calculator.default().

export = ...

// calculator.ts                                // compiled.js
// =============                                // ===========
export = class Calculator {                     // module.exports = /** @class */ (function () {
    public add(num1, num2) {                    //     function Calculator() {}
        return num1 + num2;                     //     Calculator.prototype.add = function (num1, num2) {
    }                                           //         return num1 + num2;
}                                               //     };
                                                //     return Calculator;
                                                // }());

import ... = require("module");

// importer.ts                                  // compiled.js
// ===========                                  // ===========
import Calculator = require("./calculator");    // exports.__esModule = true;
                                                // var Calculator = require("./calculator");
let calc = new Calculator();                    // var calc = new Calculator();
                                                // console.log(calc.add(2, 2));
console.log(calc.add(2, 2));                    //
Notes:
  • This syntax is only used when importing a CommonJS module.

export ... (Named Export)

// calculator.ts                                // compiled.js
// =============                                // ===========
export class Calculator {                       // exports.__esModule = true;
    public add(num1, num2) {                    // var Calculator = /** @class */ (function () {
        return num1 + num2;                     //     function Calculator() {}
    }                                           //     Calculator.prototype.add = function (num1, num2) {
}                                               //         return num1 + num2;
                                                //     };
                                                //     return Calculator;
                                                // }());
                                                // exports.Calculator = Calculator;

import { ... } from "module";

// importer.ts                                  // compiled.js
// ===========                                  // ===========
import { Calculator } from "./calculator";      // exports.__esModule = true;
                                                // var calculator = require("./calculator");
let calc = new Calculator();                    // var calc = new calculator.Calculator();
                                                // console.log(calc.add(2, 2));
console.log(calc.add(2, 2));                    //
Notes:
  • Named exports are useful to export several values.
  • During the import, you must use the same name of the corresponding object.
    Very helpful, thank you.

export default ... (Default Export)

// calculator.ts                                // compiled.js
// =============                                // ===========
export default class Calculator {               // var Calculator = /** @class */ (function () {
    public add(num1, num2) {                    //     function Calculator() {}
        return num1 + num2;                     //     Calculator.prototype.add = function (num1, num2) {
    }                                           //         return num1 + num2;
}                                               //     };
                                                //     return Calculator;
                                                // }());
                                                // exports["default"] = Calculator;

import ... from "module";

// importer.ts                                  // compiled.js
// ===========                                  // ===========
import Calculator from "./calculator";          // exports.__esModule = true;
                                                // var calculator = require("./calculator");
let calc = new Calculator();                    // var calc = new calculator["default"]();
                                                // console.log(calc.add(2, 2));
console.log(calc.add(2, 2));                    //
Notes:
  • A default export can be imported with any name.
  • Functionally equivalent to import * as Calculator from "./calculator"; and then instantiating it using new Calculator.default().

export = ...

// calculator.ts                                // compiled.js
// =============                                // ===========
export = class Calculator {                     // module.exports = /** @class */ (function () {
    public add(num1, num2) {                    //     function Calculator() {}
        return num1 + num2;                     //     Calculator.prototype.add = function (num1, num2) {
    }                                           //         return num1 + num2;
}                                               //     };
                                                //     return Calculator;
                                                // }());

import ... = require("module");

// importer.ts                                  // compiled.js
// ===========                                  // ===========
import Calculator = require("./calculator");    // exports.__esModule = true;
                                                // var Calculator = require("./calculator");
let calc = new Calculator();                    // var calc = new Calculator();
                                                // console.log(calc.add(2, 2));
console.log(calc.add(2, 2));                    //
Notes:
  • This syntax is only used when importing a CommonJS module.

export ... (Named Export)

// calculator.ts                                // compiled.js
// =============                                // ===========
export class Calculator {                       // exports.__esModule = true;
    public add(num1, num2) {                    // var Calculator = /** @class */ (function () {
        return num1 + num2;                     //     function Calculator() {}
    }                                           //     Calculator.prototype.add = function (num1, num2) {
}                                               //         return num1 + num2;
                                                //     };
                                                //     return Calculator;
                                                // }());
                                                // exports.Calculator = Calculator;

import { ... } from "module";

// importer.ts                                  // compiled.js
// ===========                                  // ===========
import { Calculator } from "./calculator";      // exports.__esModule = true;
                                                // var calculator = require("./calculator");
let calc = new Calculator();                    // var calc = new calculator.Calculator();
                                                // console.log(calc.add(2, 2));
console.log(calc.add(2, 2));                    //
Notes:
  • Named exports are useful to export several values.
  • During the import, you must use the same name of the corresponding object.
    Very helpful, thank you.

import = require does not work for me

// calculator.ts                                
// =============                              
export class Calculator {                    
    public add(num1, num2) {                    
        return num1 + num2;                 
    }                                          
}                                              


import { Calculator } from "./calculator";      

let calc = new Calculator();                 

console.log(calc.add(2, 2));                                            

image

This is most likely the wrong forum for your issue. I would suggest either Stack Overflow or creating a new issue.

I've been using TS for over a year and I'm still confused about the below. I've thrown it on stackoverflow but I bet it'll be helpful for this documentation as well.

/// file1
export {
  PORT,
  SSL_CRT,
  SSL_KEY,
}
// file2
import * as env from 'file1'
export {
   ...env  // [ts] Identifier expected. [1003] 
}



md5-d5dff0d160b3a11babed7b7d596f57e3



// file2
import * as env from 'file1'
export default {
   ...env  // [ts] Identifier expected. [1003] 
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

wmaurer picture wmaurer  路  3Comments

bgrieder picture bgrieder  路  3Comments

kyasbal-1994 picture kyasbal-1994  路  3Comments

weswigham picture weswigham  路  3Comments

seanzer picture seanzer  路  3Comments