#Cannot send ActionRowBuilder due to type error in djs 14

116 messages · Page 1 of 1 (latest)

strong pulsar

I'm trying to send a button component with a message but i get the following errors:
Type 'ActionRowBuilder<AnyComponentBuilder>' is not assignable to type 'APIActionRowComponent<APIMessageActionRowComponent> | JSONEncodable<APIActionRowComponent<APIMessageActionRowComponent>> | ActionRowData<...>'.

Property 'type' is missing in type 'ActionRowBuilder<AnyComponentBuilder>' but required in type 'ActionRowData<MessageActionRowComponentBuilder | MessageActionRowComponentData>'.

const button = new ButtonBuilder()
    .setCustomId("qac_sr")
    .setLabel("Request")
    .setStyle(ButtonStyle.Success);

    const row = new ActionRowBuilder()
    .addComponents(button)

    client.guilds.fetch("id").then((guild) => {
        (guild.channels.fetch("id") as Promise<TextChannel>).then((channel) => {
            channel.send({
                content: "Click the button below to request a test",
                components: [row] // Errors here
            })
        })
    })
wicked moonBOT

In TypeScript the ActionRowBuilder class has a generic type parameter that specifies the type of component the action row holds:

const row = new ActionRowBuilder<ButtonBuilder>().addComponents(button)
const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(selectMenu)
const row = new ActionRowBuilder<TextInputBuilder>().addComponents(textInput)
exotic mirage
strong pulsar

anyway it worked thanks

exotic mirage

yeah it’s for both ts and js there, but i’m glad it’s fixed

wispy sandal

const row = new ActionRowBuilder<ButtonBuilder>()
.addComponents(confirm);

mine is specified but it still returns

In TypeScript the ActionRowBuilder class has a generic type parameter that specifies the type of component the action row holds:
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(button)
const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(selectMenu)
const row = new ActionRowBuilder<TextInputBuilder>().addComponents(textInput)

plucky crystal
wispy sandal

in the editor it all looks fine, when i run the slash command it all works fine no errors but as soon as i try to remove it by setting it to [] it gives me the above error

exotic mirage

can you show the error you get from your console

wispy sandal
.setCustomId('confirm')
        .setLabel('Complete (Make sure auth. is saved in app)')
        .setStyle(ButtonStyle.Primary);

      const row = new ActionRowBuilder<ButtonBuilder>()
        .addComponents(confirm);

      const embed = new EmbedBuilder()
        .setColor(0x0099FF)
        .setTitle('Scan qr with Google Authenticator')
        .setImage(attachmentUrl)
        .setFooter({ text: 'Risk Mitigation unit - [RU] Mangement', iconURL: 'link.png' });

      const inmess = await msgInt?.reply({
        content: '',
        ephemeral: true,
        components: [row],
        embeds: [embed],
        files: [attachment],
      });
    } catch (error) {
      console.log('Error with QR:', error);
    }

    const collector = channel?.createMessageComponentCollector({
      max: 1,
      componentType: ComponentType.Button,
      time: 1000 * 5 * 60,
    });
    collector?.on('collect', async (collected: Collection<string, ButtonInteraction>) => {
      if (collected.first()?.customId === 'confirm') {
        await msgInt?.editReply({
          content: 'Sucesfully configured 2fa',
          components: [],
          embeds: [],
          files: [],
        })
      }
    });
  },
} as CommandObject;

code ^

error

exotic mirage

the collect event in your code doesn't return a collection so im not too sure why you set it to one

collected would return a ButtonInteraction, which you can access .customId from

but regarding that error, make sure your files are saved

wispy sandal

honestly just straight up copied the collection from wok documentation, ill change that

seemed fine

exotic mirage

im sure it works fine, but it's really not needed

also could be TS not recognizing the type after placing it for that row. try restarting your TS server & your IDe

wispy sandal

interaction is now failing no errors

exotic mirage

i would also suggest making the collector on the message instead of the channel

wispy sandal

on msgInt?

plucky crystal

I'm also seeing an editReply after a reply.
Which won't work because you've already replied to the interaction.
You can either reply to the button interaction or do an update.
Or a followUp on your main message

exotic mirage

wot

you can call editReply after a reply

wispy sandal

im editing a reply?

i dont want to send a new message

plucky crystal

eh.... I thought it was meant to be used in deferred responses. mb then

exotic mirage

editReply is exactly what it sounds like. edits the inital reply

wispy sandal
plucky crystal

Makes sense. Thanks for the correction.

plucky crystal
wispy sandal on msgInt?

You can create a collector on the message you send yes.
Rather than scoping the entire channel where the message is being sent

wispy sandal

it shows: Property 'createMessageComponentCollector' does not exist on type

exotic mirage

on type what

wispy sandal

Property 'createMessageComponentCollector' does not exist on type 'ChatInputCommandInteraction<CacheType>'

thats what i said before

exotic mirage

well yes because its not a message

wispy sandal

i cant use msgint

nor inmess

wispy sandal
exotic mirage

please show your entire code

wispy sandal

how would i make the collector on the msg instead of channel

exotic mirage

should really be in #986520997006032896 since this isn't the best channel, but this time its fine

wispy sandal
const user = '[RU] Authorization';
const service = '[RU] | Russian Federation';

export default {
  description: "generates TOTP TOKEN - ONE TIME USE",
  type: CommandType.SLASH,
  testOnly: true,
  callback: async ({ interaction: msgInt, channel }) => {
    const userId = msgInt?.user?.id;
    console.log(userId)
    const secret = userId ? userId + "" : '';
    const otpauth = authenticator.keyuri(user, service, secret);

    try {
      const imageDataUrl = await qrcode.toDataURL(otpauth);
      const buffer = Buffer.from(imageDataUrl.split(',')[1], 'base64');
      const attachment = new AttachmentBuilder(buffer, { name: 'qrcode.png' });
      const attachmentUrl = `attachment://${attachment.name}`;

      const confirm = new ButtonBuilder()
        .setCustomId('confirm')
        .setLabel('Complete (Make sure auth. is saved in app)')
        .setStyle(ButtonStyle.Primary);

      const row = new ActionRowBuilder<ButtonBuilder>()
        .addComponents(confirm);

      const embed = new EmbedBuilder()
        .setColor(0x0099FF)
        .setTitle('Scan qr with Google Authenticator')
        .setImage(attachmentUrl)
        .setFooter({ text: 'Risk Mitigation unit - [RU] Mangement', iconURL: ' });

      const inmess = await msgInt?.reply({
        content: '',
        ephemeral: true,
        components: [row],
        embeds: [embed],
        files: [attachment],
      });
    } catch (error) {
      console.log('Error with QR:', error);
    }

    const collector = msgInt?.createMessageComponentCollector({
      max: 1,
      componentType: ComponentType.Button,
      time: 1000 * 5 * 60,
    });
    collector?.on('collected', async (collected: Collection<string, ButtonInteraction>) => {
      if (collected.first()?.customId === 'confirm') {
        await msgInt?.editReply({
          content: 'Sucesfully configured 2fa',
          components: [],
          embeds: [],
          files: [],
        })
      }
    });
  },
} as CommandObject;```
exotic mirage

add fetchReply: true inside the options for inmess and i would move the catch statement lower in your code

then you can call inmess.createMessageComponentCollector(...

exotic mirage

i would move the catch statement lower in your code

wispy sandal

oops

exotic mirage

because inmess is inside the try...catch so it's not in the correct scope

wispy sandal

testing rn..

no error

exotic mirage

in that case i would do collected.update, but since you set it to a collection, you need to access a collection value first

or... use ButtonInteraction instead

wicked moonBOT
wispy sandal
exotic mirage

?

wispy sandal

collector does not respond at all?

i put in a console.log

and when i press btn nothing gets outputted

exotic mirage

the event is collect, not collected

before i was referring to your collected callback param

wispy sandal
exotic mirage
wispy sandal

how do i refer to collection

huh

exotic mirage

please look at your code to see what you named your variables

wispy sandal

magically changed lol

exotic mirage

its collected, not collection

wispy sandal

sorry

exotic mirage

it's alright, just be aware of the names

to make it easier, you could call the callback param button as an example

wispy sandal

i cant use collected.first now

so how do i check for the buttonid

exotic mirage

im still not sure why you set it to a Collection anyway

wispy sandal

no i mean i used .first() before

but i cant do that if i change to collect

exotic mirage

change what exactly?

wispy sandal

how do i check if custom id == 'confirm'

exotic mirage

you're doing that already

wispy sandal
wispy sandal

TypeError: collected.first is not a function
at C:\Users\sisar\Desktop\RiskMittigation\commands\setup.ts:55:21

exotic mirage

collect is the collector event name
collector is the name of your InteractionCollector
collected is the param for your InteractionCollector in the collect event

still not sure why you make it a collection since a InteractionCollector does not return that in the collect event

wispy sandal
wispy sandal
exotic mirage

change the collected type to ButtonInteraction

and then collected.customId

exotic mirage
wispy sandal

i mean they wrote the handler

but it indeed wasnt

wispy sandal
exotic mirage

it's a collection with a ButtonInteraction as the value

so it's not only a ButtonInteraction

wispy sandal
exotic mirage

you dont seem to understand what im saying

wispy sandal

my brain isnt working its late what do i do diffrent

yes im sorry ive been debugging this stupid program for the past 3 hours

exotic mirage
collector?.on('collect', async (collected: ButtonInteraction) => {

and then collected.customId

wispy sandal

omg

thank you so much!!!!!!

YES

FINALLY

OMG

how can i thank you

exotic mirage

the discord.js guide has great sections for making your own event & command handler if you don't want to rely on what a separate package does since it may not all be 100% correct, but this is just my suggestion

im so glad its working!

wispy sandal

thank you so much!!

i really apreciate you sticking around for so long!!

im gonna go to sleep now