Search code examples
typescriptdiscord.js

How to convert `require` to `import` within for loop?


Below is a snippet taken from: https://discordjs.guide/creating-your-bot/command-handling.html#loading-command-files

client.commands = new Collection();

const commandsPath = path.join(__dirname, 'commands');
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));

for (const file of commandFiles) {
    const filePath = path.join(commandsPath, file);
    const command = require(filePath);
    // Set a new item in the Collection with the key as the command name and the value as the exported module
    if ('data' in command && 'execute' in command) {
        client.commands.set(command.data.name, command);
    } else {
        console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`);
    }
}

Within the for loop, we retrieve the command by doing require(filePath). How do I achieve an equivalent behaviour using import?

The majority of the Discord.js guide uses CommonJS whereas I am trying to implement my bot using TypeScript.


Solution

  • The short answer is: Dont! The require function works perfectly fine in typescript, and as the typescript will transpile to javascript, the es6 syntax is purely for the ease of writing rather than performance benefits.

    The longer answer is:

    Imports can be useful for modules, structures, and many other things, but not for iterations such as your for loop, where you would have to use the import() function instead of an import statement, which works exactly the same as a require() function aside from its asynchronous return values, making the import() function entirely redundant.

    These are known as top level imports vs dynamic imports. Which you can read more on in this post

    While you can not use the import statement this doesn't mean your command structure cant entirely adapt to es6 syntax. For example you may change your command structure from something like this with commonjs exports:

    module.exports = {
      commandData: new SlashCommandBuilder()...,
      async execute(...){
        ...
      }
    }
    

    To something like this with es6 exports:

    export const commandData = new SlashCommandBuilder()...;
    export async function execute(...){
      ...
    }
    

    Both of these could be imported using the require function:

    const { commandData, execute } = require('./command');
    

    I hope this helped you, and to sum it all up: Just because the option is there, it doesn't mean it is necessary.