Search code examples
javascriptnode.jscommonjs

Calling imported class' static method throws a TypeError error


I'm trying to access a static method from an imported module I've created, but it results in throwing a TypeError error - stating that the method doesn't exist.

I've tried to export the modules differently. The method can be called if I'm using it as an instance method and not a static one, however it's not using anything which related to the class and I think it should be static.

The following static method: (Bot.js)

const Bot = class Bot {
  static getCommandIndex(message) {
    if (!message.beginsWith('/')) {
      return undefined;
    }
    return message.split(' ');
  }
}

module.exports = Bot;

The module which attempts to use it: (BotUpdateHandler.js)

const Bot = require('./Bot');
module.exports = class BotUpdateHandler {
  async handle(update) {
    const txt = update.msg.txt;
    const command = Bot.getCommandIndex(txt);
  }
}

I've already tried exporting and importing the modules like this:

// Exporting the module (Bot.js)
module.exports = { Bot };

// Importing the module (BotUpdateHandler.js)
const { Bot } = require('./Bot');

But that didn't work as well.

  TypeError: Bot.getCommandIndex is not a function

I'm using Node.js v10.16.0, it seems to work on browser-JavaScript when I checked it in the dev console (obviously though I wasn't doing any imports so I assume it's something to do with that).


Solution

  • Overview

    So I've continued to research on the problem and tried figuring what exactly the issue was.

    I'm coming from the world of C# and therefore I'm used to having using statements everywhere without a problem. However, with NodeJS, you cannot expect require to behave the same as the using statement as require - because require takes time to set up the exports and if you're having two modules depending on each other - that'll create something called circular dependencies.

    Solution

    After some digging I've found this article and this question about circular dependencies. Eventually it is best to avoid having circular dependencies in your code like listed in the answers to the linked question above (having a top module which manages the code shared between the two modules).

    However, there are also many nifty tricks to overcome this problem. The one I've used is using the require statement right before where I needed the static method to be.

    module.exports = class BotUpdateHandler {
      handle(update) {
        // eslint-disable-next-line global-require
        const Bot = require('./Bot');
        // code ....
        const txt = update.text;
        const command = Bot.getCommandIndex(txt);
      }
    }
    

    More over, I've found out you can check your code for circular dependencies (and many other useful things) using madge.