N.M. N.M. - 13 days ago 9
TypeScript Question

few questions on mixing the commonJS and ES6 module system

My questions are around working with commonJS (node style) and ES6 modules (using typescript). I have this angular 1.5 app which uses the commonJS module system. I attempted to use typescript for creating just one of the factories in the app. Few questions on the same.


  1. Can we use typescript import keyword to import a module exported
    using the commonJS module.exports syntax? For example, say we have
    RandomService.js below that we wish to use in our typescript file. I
    noticed that doing an import * as randomservice from
    '../../services/RandomService.js' threw some errors related to not
    being able to find the module. I got this to work by using a
    require(), but just wanted to know if this can be done in
    typescript?

    var randomString = require('random-string');
    module.exports = {
    getSuperRandom: function() {
    var x = 'super-random-' + randomString();
    return x;
    }
    }

  2. When we export a module from a typescript file usually the exports
    object has a property which holds our object. Even doing an export
    default results in the .default property having our exported object.
    Is there anyway where we can set the exported object directly to the
    exports object (just like we can do in commonJS module system where
    we do module.exports = 'helloservice')?


Answer
  1. Yes it's possible to import commonJS modules written in javascript, but only if typescript compiler can find declarations for these modules.

For example, if you have this javascript module in module1.js:

exports.f = function(s) {
    return s.length
}

you have to provide declaration file that describes the module and defines types for its exports, in file module1.d.ts:

export declare function f(s: string): number;

Then you can use this module with import. Typescript will find imported module if you put this code in test.ts file in the same directory as module1.d.ts:

import * as module1 from './module1';

let n: number = module1.f('z');

If you compile this code with --module=commonjs (which is the default), you will get pretty normal commonjs code as a result:

"use strict";
var module1 = require('./module1');
var n = module1.f('z');
  1. If your module exports some object, for example like this module2.js:

     module.exports = {
         a: 'a',
         n: 1
     };
    

it's better to avoid importing it using es6 syntax - es6 always assumes that module exports a namespace, not an object. In typescript, there is special syntax called import require for that:

import m2 = require('./module2');

let n1: string = m2.a;

the declaration file, module2.d.ts, must use export assignment syntax:

export = {} as {a: string, n: number};

The actual value, {}, does not matter in the declaration file and can be anything - only the type matters (which is given as type cast to unnamed interface).

If a module exports a string, as in your example, the declaration can be as simple as

export = '';