Class property doesn't exist











up vote
-1
down vote

favorite












I have been bugging on an issue, unable to find the solution. I have simplified the code to a minimum, but I still can't figure it out.



I have set up 2 basic projects with the same configuration for Babel and Typescript. One of my project is actually a module, which I import in the other project. Both of my projects are coded in Typescript, but each of them are transpiled to JS before I run them.



Both projects have the following Babel 7 configuration:



// babel.config.js
module.exports = function( api ) {

api.cache( () => process.env.NODE_ENV );

const presets = [

[
"@babel/env",
{
targets: {
node: "10",
browsers: "> 0.25%, not dead" // without this line, Babel doesn't transform the class and it works.
},
useBuiltIns: "usage",
}
],
"@babel/preset-typescript"

];

const plugins = [
// same result with or without this plugin
// the value of loose doesn't change anything
[ "@babel/plugin-proposal-class-properties", { loose: false } ]
];

return {
presets,
plugins,
};

};


Both projects have the following Typescript configuration:



// tsconfig.json
{
"compilerOptions": {
"target": "ES5", // I tried multiples values for this one
"module": "commonjs",
"allowJs": true,
"noEmit": true,
"esModuleInterop": true
}
}


My first test is to compile my class and run it without any module.
This is my source code:



//{ProjectRoot}/src/main.ts
class MOD {

public name:string;

constructor() {
this.name = "Foo";
}

getName():string {
return this.name;
}

}

const mod = new MOD();
console.log(MOD) // Output: [Function: MOD]
console.log(mod) // Output: MOD { name: 'Foo' }
console.log(mod.getName())// Output: Foo


I compile and run this source code by running:



tsc && babel ./src --out-dir dist -x .js,.ts -D --verbose --delete-dir-on-start && node dist/main


Everything runs fine, and I get the expected output in my terminal.
When I look at dist/main.js, I can see that the class has been completely rewritten by the compiler.



//{ProjectRoot}/dist/main.js
//... some code added by Babel ...
var MOD =
/*#__PURE__*/
function () {
function MOD() {
_classCallCheck(this, MOD);

_defineProperty(this, "name", void 0);

this.name = "Foo";
}

_createClass(MOD, [{
key: "getName",
value: function getName() {
return this.name;
}
}]);

return MOD;
}();


If I remove the browsers: "> 0.25%, not dead" in the Babel configuration, the compiler only adds the _defineProperty function, but keeps the rest of the code as is.



I then moved the same code to another projects, which simulates a NPM module (but in another directory, outside of the project root).



The source code of the module is:



// {moduleRoot}/src/main.ts
class MOD {

constructor() {
this.name = "Foo";
}

getName() {
return this.name;
}

}

module.exports = MOD;


The module is compiled using the same command as above.



Then in my project, I modified the source as follows:



//{ProjectRoot}/src/main.ts
//const Mod = require("../../module/dist/main"); // Works with require()
import Mod from "../../module/dist/main"; // Doesn't work with import

const mod = new Mod();
console.log(MOD) // Output: [Function: MOD]
console.log(mod) // Output: MOD { name: 'Foo' }
console.log(mod.getName())// Output: Foo


Again, it works great. I then replace the require() by the import, and things don't work anymore.
If I compile without doing the type check, then I get the correct output, meaning that Node can interpret my code.
However Typescript gives me the following error when doing the type-check:



src/main.ts:7:17 - error TS2339: Property 'getName' does not exist on type 'MOD'.

7 console.log(mod.getName())


I don't understand why the result is impacted by the way I import the module.
It seems to me that the Typescript compiler is not able to resolve the module correctly.



I have created a Gist with the source codes and the compiled code.



Any idea?



Thanks a lot!










share|improve this question




























    up vote
    -1
    down vote

    favorite












    I have been bugging on an issue, unable to find the solution. I have simplified the code to a minimum, but I still can't figure it out.



    I have set up 2 basic projects with the same configuration for Babel and Typescript. One of my project is actually a module, which I import in the other project. Both of my projects are coded in Typescript, but each of them are transpiled to JS before I run them.



    Both projects have the following Babel 7 configuration:



    // babel.config.js
    module.exports = function( api ) {

    api.cache( () => process.env.NODE_ENV );

    const presets = [

    [
    "@babel/env",
    {
    targets: {
    node: "10",
    browsers: "> 0.25%, not dead" // without this line, Babel doesn't transform the class and it works.
    },
    useBuiltIns: "usage",
    }
    ],
    "@babel/preset-typescript"

    ];

    const plugins = [
    // same result with or without this plugin
    // the value of loose doesn't change anything
    [ "@babel/plugin-proposal-class-properties", { loose: false } ]
    ];

    return {
    presets,
    plugins,
    };

    };


    Both projects have the following Typescript configuration:



    // tsconfig.json
    {
    "compilerOptions": {
    "target": "ES5", // I tried multiples values for this one
    "module": "commonjs",
    "allowJs": true,
    "noEmit": true,
    "esModuleInterop": true
    }
    }


    My first test is to compile my class and run it without any module.
    This is my source code:



    //{ProjectRoot}/src/main.ts
    class MOD {

    public name:string;

    constructor() {
    this.name = "Foo";
    }

    getName():string {
    return this.name;
    }

    }

    const mod = new MOD();
    console.log(MOD) // Output: [Function: MOD]
    console.log(mod) // Output: MOD { name: 'Foo' }
    console.log(mod.getName())// Output: Foo


    I compile and run this source code by running:



    tsc && babel ./src --out-dir dist -x .js,.ts -D --verbose --delete-dir-on-start && node dist/main


    Everything runs fine, and I get the expected output in my terminal.
    When I look at dist/main.js, I can see that the class has been completely rewritten by the compiler.



    //{ProjectRoot}/dist/main.js
    //... some code added by Babel ...
    var MOD =
    /*#__PURE__*/
    function () {
    function MOD() {
    _classCallCheck(this, MOD);

    _defineProperty(this, "name", void 0);

    this.name = "Foo";
    }

    _createClass(MOD, [{
    key: "getName",
    value: function getName() {
    return this.name;
    }
    }]);

    return MOD;
    }();


    If I remove the browsers: "> 0.25%, not dead" in the Babel configuration, the compiler only adds the _defineProperty function, but keeps the rest of the code as is.



    I then moved the same code to another projects, which simulates a NPM module (but in another directory, outside of the project root).



    The source code of the module is:



    // {moduleRoot}/src/main.ts
    class MOD {

    constructor() {
    this.name = "Foo";
    }

    getName() {
    return this.name;
    }

    }

    module.exports = MOD;


    The module is compiled using the same command as above.



    Then in my project, I modified the source as follows:



    //{ProjectRoot}/src/main.ts
    //const Mod = require("../../module/dist/main"); // Works with require()
    import Mod from "../../module/dist/main"; // Doesn't work with import

    const mod = new Mod();
    console.log(MOD) // Output: [Function: MOD]
    console.log(mod) // Output: MOD { name: 'Foo' }
    console.log(mod.getName())// Output: Foo


    Again, it works great. I then replace the require() by the import, and things don't work anymore.
    If I compile without doing the type check, then I get the correct output, meaning that Node can interpret my code.
    However Typescript gives me the following error when doing the type-check:



    src/main.ts:7:17 - error TS2339: Property 'getName' does not exist on type 'MOD'.

    7 console.log(mod.getName())


    I don't understand why the result is impacted by the way I import the module.
    It seems to me that the Typescript compiler is not able to resolve the module correctly.



    I have created a Gist with the source codes and the compiled code.



    Any idea?



    Thanks a lot!










    share|improve this question


























      up vote
      -1
      down vote

      favorite









      up vote
      -1
      down vote

      favorite











      I have been bugging on an issue, unable to find the solution. I have simplified the code to a minimum, but I still can't figure it out.



      I have set up 2 basic projects with the same configuration for Babel and Typescript. One of my project is actually a module, which I import in the other project. Both of my projects are coded in Typescript, but each of them are transpiled to JS before I run them.



      Both projects have the following Babel 7 configuration:



      // babel.config.js
      module.exports = function( api ) {

      api.cache( () => process.env.NODE_ENV );

      const presets = [

      [
      "@babel/env",
      {
      targets: {
      node: "10",
      browsers: "> 0.25%, not dead" // without this line, Babel doesn't transform the class and it works.
      },
      useBuiltIns: "usage",
      }
      ],
      "@babel/preset-typescript"

      ];

      const plugins = [
      // same result with or without this plugin
      // the value of loose doesn't change anything
      [ "@babel/plugin-proposal-class-properties", { loose: false } ]
      ];

      return {
      presets,
      plugins,
      };

      };


      Both projects have the following Typescript configuration:



      // tsconfig.json
      {
      "compilerOptions": {
      "target": "ES5", // I tried multiples values for this one
      "module": "commonjs",
      "allowJs": true,
      "noEmit": true,
      "esModuleInterop": true
      }
      }


      My first test is to compile my class and run it without any module.
      This is my source code:



      //{ProjectRoot}/src/main.ts
      class MOD {

      public name:string;

      constructor() {
      this.name = "Foo";
      }

      getName():string {
      return this.name;
      }

      }

      const mod = new MOD();
      console.log(MOD) // Output: [Function: MOD]
      console.log(mod) // Output: MOD { name: 'Foo' }
      console.log(mod.getName())// Output: Foo


      I compile and run this source code by running:



      tsc && babel ./src --out-dir dist -x .js,.ts -D --verbose --delete-dir-on-start && node dist/main


      Everything runs fine, and I get the expected output in my terminal.
      When I look at dist/main.js, I can see that the class has been completely rewritten by the compiler.



      //{ProjectRoot}/dist/main.js
      //... some code added by Babel ...
      var MOD =
      /*#__PURE__*/
      function () {
      function MOD() {
      _classCallCheck(this, MOD);

      _defineProperty(this, "name", void 0);

      this.name = "Foo";
      }

      _createClass(MOD, [{
      key: "getName",
      value: function getName() {
      return this.name;
      }
      }]);

      return MOD;
      }();


      If I remove the browsers: "> 0.25%, not dead" in the Babel configuration, the compiler only adds the _defineProperty function, but keeps the rest of the code as is.



      I then moved the same code to another projects, which simulates a NPM module (but in another directory, outside of the project root).



      The source code of the module is:



      // {moduleRoot}/src/main.ts
      class MOD {

      constructor() {
      this.name = "Foo";
      }

      getName() {
      return this.name;
      }

      }

      module.exports = MOD;


      The module is compiled using the same command as above.



      Then in my project, I modified the source as follows:



      //{ProjectRoot}/src/main.ts
      //const Mod = require("../../module/dist/main"); // Works with require()
      import Mod from "../../module/dist/main"; // Doesn't work with import

      const mod = new Mod();
      console.log(MOD) // Output: [Function: MOD]
      console.log(mod) // Output: MOD { name: 'Foo' }
      console.log(mod.getName())// Output: Foo


      Again, it works great. I then replace the require() by the import, and things don't work anymore.
      If I compile without doing the type check, then I get the correct output, meaning that Node can interpret my code.
      However Typescript gives me the following error when doing the type-check:



      src/main.ts:7:17 - error TS2339: Property 'getName' does not exist on type 'MOD'.

      7 console.log(mod.getName())


      I don't understand why the result is impacted by the way I import the module.
      It seems to me that the Typescript compiler is not able to resolve the module correctly.



      I have created a Gist with the source codes and the compiled code.



      Any idea?



      Thanks a lot!










      share|improve this question















      I have been bugging on an issue, unable to find the solution. I have simplified the code to a minimum, but I still can't figure it out.



      I have set up 2 basic projects with the same configuration for Babel and Typescript. One of my project is actually a module, which I import in the other project. Both of my projects are coded in Typescript, but each of them are transpiled to JS before I run them.



      Both projects have the following Babel 7 configuration:



      // babel.config.js
      module.exports = function( api ) {

      api.cache( () => process.env.NODE_ENV );

      const presets = [

      [
      "@babel/env",
      {
      targets: {
      node: "10",
      browsers: "> 0.25%, not dead" // without this line, Babel doesn't transform the class and it works.
      },
      useBuiltIns: "usage",
      }
      ],
      "@babel/preset-typescript"

      ];

      const plugins = [
      // same result with or without this plugin
      // the value of loose doesn't change anything
      [ "@babel/plugin-proposal-class-properties", { loose: false } ]
      ];

      return {
      presets,
      plugins,
      };

      };


      Both projects have the following Typescript configuration:



      // tsconfig.json
      {
      "compilerOptions": {
      "target": "ES5", // I tried multiples values for this one
      "module": "commonjs",
      "allowJs": true,
      "noEmit": true,
      "esModuleInterop": true
      }
      }


      My first test is to compile my class and run it without any module.
      This is my source code:



      //{ProjectRoot}/src/main.ts
      class MOD {

      public name:string;

      constructor() {
      this.name = "Foo";
      }

      getName():string {
      return this.name;
      }

      }

      const mod = new MOD();
      console.log(MOD) // Output: [Function: MOD]
      console.log(mod) // Output: MOD { name: 'Foo' }
      console.log(mod.getName())// Output: Foo


      I compile and run this source code by running:



      tsc && babel ./src --out-dir dist -x .js,.ts -D --verbose --delete-dir-on-start && node dist/main


      Everything runs fine, and I get the expected output in my terminal.
      When I look at dist/main.js, I can see that the class has been completely rewritten by the compiler.



      //{ProjectRoot}/dist/main.js
      //... some code added by Babel ...
      var MOD =
      /*#__PURE__*/
      function () {
      function MOD() {
      _classCallCheck(this, MOD);

      _defineProperty(this, "name", void 0);

      this.name = "Foo";
      }

      _createClass(MOD, [{
      key: "getName",
      value: function getName() {
      return this.name;
      }
      }]);

      return MOD;
      }();


      If I remove the browsers: "> 0.25%, not dead" in the Babel configuration, the compiler only adds the _defineProperty function, but keeps the rest of the code as is.



      I then moved the same code to another projects, which simulates a NPM module (but in another directory, outside of the project root).



      The source code of the module is:



      // {moduleRoot}/src/main.ts
      class MOD {

      constructor() {
      this.name = "Foo";
      }

      getName() {
      return this.name;
      }

      }

      module.exports = MOD;


      The module is compiled using the same command as above.



      Then in my project, I modified the source as follows:



      //{ProjectRoot}/src/main.ts
      //const Mod = require("../../module/dist/main"); // Works with require()
      import Mod from "../../module/dist/main"; // Doesn't work with import

      const mod = new Mod();
      console.log(MOD) // Output: [Function: MOD]
      console.log(mod) // Output: MOD { name: 'Foo' }
      console.log(mod.getName())// Output: Foo


      Again, it works great. I then replace the require() by the import, and things don't work anymore.
      If I compile without doing the type check, then I get the correct output, meaning that Node can interpret my code.
      However Typescript gives me the following error when doing the type-check:



      src/main.ts:7:17 - error TS2339: Property 'getName' does not exist on type 'MOD'.

      7 console.log(mod.getName())


      I don't understand why the result is impacted by the way I import the module.
      It seems to me that the Typescript compiler is not able to resolve the module correctly.



      I have created a Gist with the source codes and the compiled code.



      Any idea?



      Thanks a lot!







      typescript






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 11 at 3:09

























      asked Nov 11 at 2:19









      h-Reser

      32




      32
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote



          accepted










          Since the project is importing module/dist/main, and only a .js file exists at that path, the only type information the TypeScript compiler has for that import is what it can extract from main.js, which in general is going to be incomplete. What you should probably do is have tsc on the module generate .d.ts files alongside the .js files. Then tsc on the project will use the .d.ts files. E.g., change module/tsconfig.json to the following:



          {
          "compilerOptions": {
          "target": "ES5",
          "module": "commonjs",
          "rootDir": "src",
          "outDir": "dist",
          "declaration": true,
          "emitDeclarationOnly": true,
          "esModuleInterop": true
          }
          }


          (Note that allowJs has to be removed because it is incompatible with declaration. If you needed allowJs, please explain your scenario and I'll try to help you solve it.) And compile the module with this command:



          rm -rf dist && tsc && babel ./src --out-dir dist -x .js,.ts -D --verbose


          You'll also have to change the export at the end of module/src/main.ts to:



          export default MOD;


          because the TypeScript compiler does not recognize assignments to module.exports in a .ts file and Babel does not support export = MOD. This should work as long as all consumers of the module use a default import. (Again, if you need to support consumers that do a plain require, please explain your scenario and I'll see what I can do.)



          Update



          If you need an export assignment, since your .ts file will need to say export = MOD and Babel doesn't accept that, the only solution I can find is to run Babel on the JavaScript generated by tsc in which the export = MOD will have been translated to module.exports = MOD. In an example configuration, module/tsconfig.json is:



          {
          "compilerOptions": {
          "target": "ES6",
          "module": "commonjs",
          "rootDir": "src",
          "outDir": "ts-out",
          "declarationDir": "dist",
          "declaration": true,
          "esModuleInterop": true
          }
          }


          and the build command is:



          rm -rf dist ts-out && tsc && babel ./ts-out --out-dir dist -x .js,.ts -D --verbose


          (This is assuming you have some reason to use Babel at all rather than using the JavaScript output of tsc directly.)






          share|improve this answer























          • Yes, your solution works indeed. But as you said it no longer works with require, which is something that I want. I want anyone to be able to use my module, whether it's with CommonJS or ES Modules.When I download a package on NPM, I can usually use both systems. Take one example, Express, they use module.exports, which is why I tried this way. I'm surprised that it doesn't work with my module. I don't really understand the difference.
            – h-Reser
            Nov 11 at 4:23












          • See the updated answer for how to make require work.
            – Matt McCutchen
            Nov 11 at 4:43










          • I managed to do it. I think I was lacking some comprehension of the CommonJS and ES modules. Thanks a lot for looking into that, you were a big help :)
            – h-Reser
            Nov 11 at 20:08











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53245289%2fclass-property-doesnt-exist%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          0
          down vote



          accepted










          Since the project is importing module/dist/main, and only a .js file exists at that path, the only type information the TypeScript compiler has for that import is what it can extract from main.js, which in general is going to be incomplete. What you should probably do is have tsc on the module generate .d.ts files alongside the .js files. Then tsc on the project will use the .d.ts files. E.g., change module/tsconfig.json to the following:



          {
          "compilerOptions": {
          "target": "ES5",
          "module": "commonjs",
          "rootDir": "src",
          "outDir": "dist",
          "declaration": true,
          "emitDeclarationOnly": true,
          "esModuleInterop": true
          }
          }


          (Note that allowJs has to be removed because it is incompatible with declaration. If you needed allowJs, please explain your scenario and I'll try to help you solve it.) And compile the module with this command:



          rm -rf dist && tsc && babel ./src --out-dir dist -x .js,.ts -D --verbose


          You'll also have to change the export at the end of module/src/main.ts to:



          export default MOD;


          because the TypeScript compiler does not recognize assignments to module.exports in a .ts file and Babel does not support export = MOD. This should work as long as all consumers of the module use a default import. (Again, if you need to support consumers that do a plain require, please explain your scenario and I'll see what I can do.)



          Update



          If you need an export assignment, since your .ts file will need to say export = MOD and Babel doesn't accept that, the only solution I can find is to run Babel on the JavaScript generated by tsc in which the export = MOD will have been translated to module.exports = MOD. In an example configuration, module/tsconfig.json is:



          {
          "compilerOptions": {
          "target": "ES6",
          "module": "commonjs",
          "rootDir": "src",
          "outDir": "ts-out",
          "declarationDir": "dist",
          "declaration": true,
          "esModuleInterop": true
          }
          }


          and the build command is:



          rm -rf dist ts-out && tsc && babel ./ts-out --out-dir dist -x .js,.ts -D --verbose


          (This is assuming you have some reason to use Babel at all rather than using the JavaScript output of tsc directly.)






          share|improve this answer























          • Yes, your solution works indeed. But as you said it no longer works with require, which is something that I want. I want anyone to be able to use my module, whether it's with CommonJS or ES Modules.When I download a package on NPM, I can usually use both systems. Take one example, Express, they use module.exports, which is why I tried this way. I'm surprised that it doesn't work with my module. I don't really understand the difference.
            – h-Reser
            Nov 11 at 4:23












          • See the updated answer for how to make require work.
            – Matt McCutchen
            Nov 11 at 4:43










          • I managed to do it. I think I was lacking some comprehension of the CommonJS and ES modules. Thanks a lot for looking into that, you were a big help :)
            – h-Reser
            Nov 11 at 20:08















          up vote
          0
          down vote



          accepted










          Since the project is importing module/dist/main, and only a .js file exists at that path, the only type information the TypeScript compiler has for that import is what it can extract from main.js, which in general is going to be incomplete. What you should probably do is have tsc on the module generate .d.ts files alongside the .js files. Then tsc on the project will use the .d.ts files. E.g., change module/tsconfig.json to the following:



          {
          "compilerOptions": {
          "target": "ES5",
          "module": "commonjs",
          "rootDir": "src",
          "outDir": "dist",
          "declaration": true,
          "emitDeclarationOnly": true,
          "esModuleInterop": true
          }
          }


          (Note that allowJs has to be removed because it is incompatible with declaration. If you needed allowJs, please explain your scenario and I'll try to help you solve it.) And compile the module with this command:



          rm -rf dist && tsc && babel ./src --out-dir dist -x .js,.ts -D --verbose


          You'll also have to change the export at the end of module/src/main.ts to:



          export default MOD;


          because the TypeScript compiler does not recognize assignments to module.exports in a .ts file and Babel does not support export = MOD. This should work as long as all consumers of the module use a default import. (Again, if you need to support consumers that do a plain require, please explain your scenario and I'll see what I can do.)



          Update



          If you need an export assignment, since your .ts file will need to say export = MOD and Babel doesn't accept that, the only solution I can find is to run Babel on the JavaScript generated by tsc in which the export = MOD will have been translated to module.exports = MOD. In an example configuration, module/tsconfig.json is:



          {
          "compilerOptions": {
          "target": "ES6",
          "module": "commonjs",
          "rootDir": "src",
          "outDir": "ts-out",
          "declarationDir": "dist",
          "declaration": true,
          "esModuleInterop": true
          }
          }


          and the build command is:



          rm -rf dist ts-out && tsc && babel ./ts-out --out-dir dist -x .js,.ts -D --verbose


          (This is assuming you have some reason to use Babel at all rather than using the JavaScript output of tsc directly.)






          share|improve this answer























          • Yes, your solution works indeed. But as you said it no longer works with require, which is something that I want. I want anyone to be able to use my module, whether it's with CommonJS or ES Modules.When I download a package on NPM, I can usually use both systems. Take one example, Express, they use module.exports, which is why I tried this way. I'm surprised that it doesn't work with my module. I don't really understand the difference.
            – h-Reser
            Nov 11 at 4:23












          • See the updated answer for how to make require work.
            – Matt McCutchen
            Nov 11 at 4:43










          • I managed to do it. I think I was lacking some comprehension of the CommonJS and ES modules. Thanks a lot for looking into that, you were a big help :)
            – h-Reser
            Nov 11 at 20:08













          up vote
          0
          down vote



          accepted







          up vote
          0
          down vote



          accepted






          Since the project is importing module/dist/main, and only a .js file exists at that path, the only type information the TypeScript compiler has for that import is what it can extract from main.js, which in general is going to be incomplete. What you should probably do is have tsc on the module generate .d.ts files alongside the .js files. Then tsc on the project will use the .d.ts files. E.g., change module/tsconfig.json to the following:



          {
          "compilerOptions": {
          "target": "ES5",
          "module": "commonjs",
          "rootDir": "src",
          "outDir": "dist",
          "declaration": true,
          "emitDeclarationOnly": true,
          "esModuleInterop": true
          }
          }


          (Note that allowJs has to be removed because it is incompatible with declaration. If you needed allowJs, please explain your scenario and I'll try to help you solve it.) And compile the module with this command:



          rm -rf dist && tsc && babel ./src --out-dir dist -x .js,.ts -D --verbose


          You'll also have to change the export at the end of module/src/main.ts to:



          export default MOD;


          because the TypeScript compiler does not recognize assignments to module.exports in a .ts file and Babel does not support export = MOD. This should work as long as all consumers of the module use a default import. (Again, if you need to support consumers that do a plain require, please explain your scenario and I'll see what I can do.)



          Update



          If you need an export assignment, since your .ts file will need to say export = MOD and Babel doesn't accept that, the only solution I can find is to run Babel on the JavaScript generated by tsc in which the export = MOD will have been translated to module.exports = MOD. In an example configuration, module/tsconfig.json is:



          {
          "compilerOptions": {
          "target": "ES6",
          "module": "commonjs",
          "rootDir": "src",
          "outDir": "ts-out",
          "declarationDir": "dist",
          "declaration": true,
          "esModuleInterop": true
          }
          }


          and the build command is:



          rm -rf dist ts-out && tsc && babel ./ts-out --out-dir dist -x .js,.ts -D --verbose


          (This is assuming you have some reason to use Babel at all rather than using the JavaScript output of tsc directly.)






          share|improve this answer














          Since the project is importing module/dist/main, and only a .js file exists at that path, the only type information the TypeScript compiler has for that import is what it can extract from main.js, which in general is going to be incomplete. What you should probably do is have tsc on the module generate .d.ts files alongside the .js files. Then tsc on the project will use the .d.ts files. E.g., change module/tsconfig.json to the following:



          {
          "compilerOptions": {
          "target": "ES5",
          "module": "commonjs",
          "rootDir": "src",
          "outDir": "dist",
          "declaration": true,
          "emitDeclarationOnly": true,
          "esModuleInterop": true
          }
          }


          (Note that allowJs has to be removed because it is incompatible with declaration. If you needed allowJs, please explain your scenario and I'll try to help you solve it.) And compile the module with this command:



          rm -rf dist && tsc && babel ./src --out-dir dist -x .js,.ts -D --verbose


          You'll also have to change the export at the end of module/src/main.ts to:



          export default MOD;


          because the TypeScript compiler does not recognize assignments to module.exports in a .ts file and Babel does not support export = MOD. This should work as long as all consumers of the module use a default import. (Again, if you need to support consumers that do a plain require, please explain your scenario and I'll see what I can do.)



          Update



          If you need an export assignment, since your .ts file will need to say export = MOD and Babel doesn't accept that, the only solution I can find is to run Babel on the JavaScript generated by tsc in which the export = MOD will have been translated to module.exports = MOD. In an example configuration, module/tsconfig.json is:



          {
          "compilerOptions": {
          "target": "ES6",
          "module": "commonjs",
          "rootDir": "src",
          "outDir": "ts-out",
          "declarationDir": "dist",
          "declaration": true,
          "esModuleInterop": true
          }
          }


          and the build command is:



          rm -rf dist ts-out && tsc && babel ./ts-out --out-dir dist -x .js,.ts -D --verbose


          (This is assuming you have some reason to use Babel at all rather than using the JavaScript output of tsc directly.)







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 11 at 4:42

























          answered Nov 11 at 3:46









          Matt McCutchen

          13k719




          13k719












          • Yes, your solution works indeed. But as you said it no longer works with require, which is something that I want. I want anyone to be able to use my module, whether it's with CommonJS or ES Modules.When I download a package on NPM, I can usually use both systems. Take one example, Express, they use module.exports, which is why I tried this way. I'm surprised that it doesn't work with my module. I don't really understand the difference.
            – h-Reser
            Nov 11 at 4:23












          • See the updated answer for how to make require work.
            – Matt McCutchen
            Nov 11 at 4:43










          • I managed to do it. I think I was lacking some comprehension of the CommonJS and ES modules. Thanks a lot for looking into that, you were a big help :)
            – h-Reser
            Nov 11 at 20:08


















          • Yes, your solution works indeed. But as you said it no longer works with require, which is something that I want. I want anyone to be able to use my module, whether it's with CommonJS or ES Modules.When I download a package on NPM, I can usually use both systems. Take one example, Express, they use module.exports, which is why I tried this way. I'm surprised that it doesn't work with my module. I don't really understand the difference.
            – h-Reser
            Nov 11 at 4:23












          • See the updated answer for how to make require work.
            – Matt McCutchen
            Nov 11 at 4:43










          • I managed to do it. I think I was lacking some comprehension of the CommonJS and ES modules. Thanks a lot for looking into that, you were a big help :)
            – h-Reser
            Nov 11 at 20:08
















          Yes, your solution works indeed. But as you said it no longer works with require, which is something that I want. I want anyone to be able to use my module, whether it's with CommonJS or ES Modules.When I download a package on NPM, I can usually use both systems. Take one example, Express, they use module.exports, which is why I tried this way. I'm surprised that it doesn't work with my module. I don't really understand the difference.
          – h-Reser
          Nov 11 at 4:23






          Yes, your solution works indeed. But as you said it no longer works with require, which is something that I want. I want anyone to be able to use my module, whether it's with CommonJS or ES Modules.When I download a package on NPM, I can usually use both systems. Take one example, Express, they use module.exports, which is why I tried this way. I'm surprised that it doesn't work with my module. I don't really understand the difference.
          – h-Reser
          Nov 11 at 4:23














          See the updated answer for how to make require work.
          – Matt McCutchen
          Nov 11 at 4:43




          See the updated answer for how to make require work.
          – Matt McCutchen
          Nov 11 at 4:43












          I managed to do it. I think I was lacking some comprehension of the CommonJS and ES modules. Thanks a lot for looking into that, you were a big help :)
          – h-Reser
          Nov 11 at 20:08




          I managed to do it. I think I was lacking some comprehension of the CommonJS and ES modules. Thanks a lot for looking into that, you were a big help :)
          – h-Reser
          Nov 11 at 20:08


















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53245289%2fclass-property-doesnt-exist%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Full-time equivalent

          Bicuculline

          さくらももこ