Search code examples
typescripttsc

Typescript name generation mechanism


We are trying to organize an older package. In order to this we started to change the original "export = module" form to "export default module". This change breaks an other part of the code which uses eval(), since the "import module from 'module'" is being compiled to "module_1". The code fed to eval() arrives from an external source, whereas we want to use module, not the "module_1.default" form.

How this kind of naming convention actually works? Could you tell us the concept and how can we use the original module name instead of the compiled one? Or is there a function to get the actual name of the module after compilation?

Thanks, Adam


Solution

  • It's unsafe to use the name generated by the compiler. It could be changed.

    A workaround

    But you can do:

    import myModule from 'module'
    const module = myModule
    

    The second line will be compiled to:

    var module = module_1.default;
    

    Then, you can use the variable module.

    Why to use export default rather than export =

    In the near future, the use of export default will become the norm. This feature is designed by ECMAScript to replace the current CommonJS use case. A member default is just better, more generic.

    Here is an example. You need to export an object:

    const myConfigObject = Object.freeze({
        dbHost: "",
        dbUser: "",
        // ...
    })
    export = myConfigObject
    

    Then, you can import it:

    import * as myConfigObject from "./myConfigObject"
    

    Subsequently, you would like to export a small helper function toDSN that helps the module user to do something related to the exported object. How to do that? You could add the helper as a member of the configuration. But it wouldn't be elegant.

    Here is the ES6 way:

    export default Object.freeze({
        dbHost: "",
        dbUser: "",
        // ...
    })
    export function toDSN(configObj) {
        return // ...
    }
    

    Then, you can import the default object:

    import myConfigObject from "./myConfigObject"
    

    ... or import toDSN:

    import { toDSN } from "./myConfigObject"
    

    ... or import both:

    import myConfigObject, { toDSN } from "./myConfigObject"
    

    The only small pitfall is for current Node.js user code: a member default must be used. When Node.js will implement ES6 modules, the pitfall won't exist anymore.

    Why the TS compiler generates an intermediate variable for imports?

    Because it is needed by the general case of ES6 modules. The following ES6 code:

    import myConfigObject, { toDSN } from "./myConfigObject"
    

    Here, two variables are imported. But a CommonJS (or AMD) require can only import a single variable. So, the compiler imports this single variable as an intermediate variable myConfigObject_1. Then, the object myConfigObject is available through myConfigObject_1.default and toDSN is available through myConfigObject_1.toDSN.

    I suggest the article from Mozilla for an introduction to ES6 modules.