Search code examples
node.jstypescriptdiscorddiscord.js

Discord.js | interaction.reply is not a function [SlashCommand][Typescript]


I am making a /ping command in my bot, following the discordjs guide, but when I use the command, I get an error:

TypeError: interaction.reply is not a function
    at Object.<anonymous> (C:\Users\timda\code\discord bot\bot-data\commands\ping.ts:8:15)
    at Generator.next (<anonymous>)
    at C:\Users\timda\code\discord bot\bot-data\commands\ping.ts:8:71
    at new Promise (<anonymous>)
    at __awaiter (C:\Users\timda\code\discord bot\bot-data\commands\ping.ts:4:12)
    at Object.execute (C:\Users\timda\code\discord bot\bot-data\commands\ping.ts:18:16)   
    at C:\Users\timda\code\discord bot\main.ts:43:18
    at Generator.next (<anonymous>)
    at C:\Users\timda\code\discord bot\main.ts:8:71
    at new Promise (<anonymous>)

This is the /ping commands code:

import { SlashCommandBuilder } from 'discord.js';

module.exports = {
    data: new SlashCommandBuilder()
        .setName('ping')
        .setDescription('Replies with Pong!'),
    async execute(interaction: { reply: (arg0: string) => any }) {
        console.log(interaction);
        interaction.reply('Pong!');
    },
};

And here is the code in my main file that loads in the SlashCommand files:

import fs from 'node:fs';
import path from 'node:path';
import { Client, Collection, GatewayIntentBits, Partials, REST, Routes } from 'discord.js';
import { clientId, token } from './config.json';

const client = new Client({ 
    intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.DirectMessages, GatewayIntentBits.MessageContent],
    partials: [Partials.Message, Partials.Channel],
    presence: { status: 'online', activities: [{ name: 'you 👀', type: 3 }] }
});

(client as any).commands = new Collection();
const commands: any[] = [];

for (const file of (fs.readdirSync(path.join('./bot-data/commands')).filter(file => file.endsWith('.ts')))) {
    const command = require(`./bot-data/commands/${file}`);
    (client as any).commands.set(command.data.name, command);
    commands.push(command.data.toJSON());
};

client.on('ready', async (client: { user: { tag: any; }; }) => {
    const rest = new REST({ version: '10' }).setToken(token);

    try {
        await rest.put(Routes.applicationCommands(clientId), { body: commands});
    } catch (error) {
        console.error(error);
    }

    console.log(`Succesfully logged in as ${client.user.tag}!`);
});

client.on('interactionCreate', async interaction => {
    if(interaction.isCommand()) {
        const command = (client as any).commands.get(interaction.commandName);

        if (!command) {
            await interaction.reply({content: `Something went wrong while executing ${interaction.commandName}.`, ephemeral: true});
            return;
        }

        try {
            await command.execute(client, interaction);
        } catch (error) {
            await interaction.reply({content: `Something went wrong while executing ${interaction.commandName}., ephemeral: true});
            console.error(error);
        }
    }
});

The command does get loaded when /ping is used, because it does log the interaction in the console. I am writing the bot in Typescript, that's why I did interaction: { reply: (arg0: string) => any } and I'm using node to compile and run it. NVM: version 1.1.10 NPM: version 8.19.2

I've tried writing interaction: { reply: (arg0: string) => any } in different ways and I've also already done a lot of googling, but I can't find the problem I'm facing here. If someone could help me I would appreciate it.


Solution

  • Inside of main.ts, you're calling the execute function with these arguments:

    await command.execute(client, interaction);
    

    But inside of ping.ts, you're only accepting these arguments:

    async execute(interaction: { reply: (arg0: string) => any }) { // etc
    

    You need to include both client and interaction as arguments in ping.ts to prevent the values being passed into the wrong variables.

    // I'm fairly certain that these are the right imports
    import { BaseInteraction, SlashCommandBuilder, Client} from 'discord.js';
    ...
    async execute(client: Client, interaction: BaseInteraction) { // etc