TypeScript export CommonJS and ES Modules


TL;DR: To export to both CommonJS and ES Modules in TypeScript, set the default property in the export:

myModule.default = myModule;
export = myModule;

Prerequisites

Install typescript globally (if you haven’t already):

$ npm install --global typescript

Given function myModule:

// index.ts
const myModule = () => {};

CommonJS

To export default in CommonJS:

// index.ts
// ...
export = myModule;

Verify the output by running tsc index.ts:

// index.js
'use strict';
var myModule = function() {};
module.exports = myModule;

This means you can require with CommonJS:

const myModule = require('./index');

But importing with ES Modules will cause the error:

error TS1259: Module '"index"' can only be default-imported using the 'esModuleInterop' flag

1 import myModule from './index';
         ~~~~~~~~

  index.ts:3:1
    3 export = myModule;
      ~~~~~~~~~~~~~~~~~~
    This module is declared with using 'export =', and can only be used with a default import when using the 'esModuleInterop' flag.


Found 1 error.

ES Modules

To export default in ES Modules:

// index.ts
// ...
export default myModule;

Verify the output by running tsc index.ts:

// index.js
'use strict';
exports.__esModule = true;
var myModule = function() {};
exports['default'] = myModule;

This means you can import with ES Modules:

import myModule from './index';

But requiring with CommonJS means you’ll need to use the default property:

const myModule = require('./index').default;

CommonJS + ES Modules

If you try to export both CommonJS and ES Modules:

// index.ts
// ...
export = myModule;
export default myModule;

You’ll get the error:

$ tsc index.ts
index.ts:3:1 - error TS2309: An export assignment cannot be used in a module with other exported elements.

3 export = myModule;
  ~~~~~~~~~~~~~~~~~~


Found 1 error.

So how do we allow for interoperability? We can copy Babel’s approach and set the default property on the main export object:

// index.ts
// ...
myModule.default = myModule;
export = myModule;

This works for myModule since a Function is an instance of Object in JavaScript.

As a result, you can import with both CommonJS and ES Module syntax:

// CommonJS
const myModule = require('./index');

// ES Modules
import myModule from './index';


If you enjoyed this post, please consider supporting this site!