discordjs / builders

A collection of builders that you can use when creating your bot.
Apache License 2.0
97 stars 37 forks source link

Interface for SlashCommandBuilder#toJSON() #32

Closed mahyarmirrashed closed 2 years ago

mahyarmirrashed commented 3 years ago

Is your feature request related to a problem? Please describe. I create my slash commands in each of their own files. Each file exports a constant variable whose value is constructed using the slash command builder at runtime.

Describe the ideal solution Add something like this in SlashCommandBuilder.d.ts:

type SlashCommandJSON = {
  name: string;
  description: string;
  options: APIApplicationCommandOption[];
  default_permission: boolean | undefined;
};

export default SlashCommandJSON;

Describe alternatives you've considered The alternative is for me to create that file for myself and just reuse it for other projects.

Additional context No additional context to provide.

megatank58 commented 3 years ago

type ApplicationCommandData is there in index.d.ts in the main discord.js repository which does this

vladfrangu commented 3 years ago

The return type of the builder can be accessed either by doing type SlashCommandJSON = ReturnType<SlashCommandBuilder['toJSON']>; or by importing the type from discord-api-types. Am I missing something?

mahyarmirrashed commented 3 years ago

type ApplicationCommandData is there in index.d.ts in the main discord.js repository which does this

As far as I can tell, this solution does not work. I tried replacing SlashCommandJSON with your suggestion but VSCode reports errors:

export const json: ApplicationCommandData = new SlashCommandBuilder()
  .setName('add')
  .setDescription('Activate a new IEEE member on the server.')
  .setDefaultPermission(true)
  .addUserOption((option: SlashCommandUserOption) =>
    option
      .setName('user')
      .setDescription(
        'Mention user to associate with the IEEE membership number.',
      )
      .setRequired(true),
  )
  .addIntegerOption((option: SlashCommandIntegerOption) =>
    option
      .setName('ieee_number')
      .setDescription('IEEE membership number to associate with user.')
      .setRequired(true),
  )
  .toJSON();
mahyarmirrashed commented 3 years ago

The return type of the builder can be accessed either by doing type SlashCommandJSON = ReturnType<SlashCommandBuilder['toJSON']>; or by importing the type from discord-api-types. Am I missing something?

I think the solution of type SlashCommandJSON = ReturnType<SlashCommandBuilder['toJSON']>; is totally valid. However, would it not be better to implement the object as its own interface so that you did not need to know this fancy TS?

I am also curious if you could link to what you were mentioning about the discord-api-types.

vladfrangu commented 3 years ago

Oh, snap... what's the vscode error you're receiving? I think I might've found a typings bug to be fair, but i'll need to test it out first locally when I get home

DTrombett commented 3 years ago

Not sure if it's related to this issue but the type of SlashCommandBuilder#toJSON() is not compatible with the type of the parameter in ApplicationCommandManager#create(), so

{
  name: string;
  description: string;
  options: APIApplicationCommandOption[];
  default_permission: boolean | undefined;
}

is not assignable to the djs' ApplicationCommandData, which causes an error if using something like:

declare const cmd: SlashCommandBuilder;
client.application.commands.create(cmd.toJSON())

image1 image2

mahyarmirrashed commented 3 years ago

Oh, snap... what's the vscode error you're receiving? I think I might've found a typings bug to be fair, but i'll need to test it out first locally when I get home

With ApplicationCommandData:

Type '{ name: string; description: string; options: APIApplicationCommandOption[]; default_permission: boolean | undefined; }' is not assignable to type 'ApplicationCommandData'.
  Type '{ name: string; description: string; options: APIApplicationCommandOption[]; default_permission: boolean | undefined; }' is not assignable to type 'ChatInputApplicationCommandData'.
    Types of property 'options' are incompatible.
      Type 'APIApplicationCommandOption[]' is not assignable to type 'ApplicationCommandOptionData[]'.
        Type 'APIApplicationCommandOption' is not assignable to type 'ApplicationCommandOptionData'.
          Type 'APIApplicationCommandArgumentOptions' is not assignable to type 'ApplicationCommandOptionData'.
            Type 'APIApplicationCommandArgumentOptions' is not assignable to type 'ApplicationCommandChoicesData'.
              Types of property 'type' are incompatible.
                Type 'ApplicationCommandOptionType.String | ApplicationCommandOptionType.Integer | ApplicationCommandOptionType.Number' is not assignable to type 'CommandOptionChoiceResolvableType'.
                  Type 'ApplicationCommandOptionType.String' is not assignable to type 'CommandOptionChoiceResolvableType'.ts(2322)
Khasms commented 3 years ago

Not sure if it's related to this issue but the type of SlashCommandBuilder#toJSON() is not compatible with the type of the parameter in ApplicationCommandManager#create(), so

This is intended. toJSON returns the API compatible type, but create is made to use JS norms, such as camelCase. If you believe create should accept the API type, then it would probably be better to make an issue on the main repo as it is not an issue with builders.

vladfrangu commented 3 years ago

This is a double bug: The return type for SlashCommandBuilder#toJSON isn't properly typed to the API data, as well as discord.js not supporting raw data (which is a different issue altogether, and should be opened in that repository!)

DTrombett commented 3 years ago

Oh is there a type in the discord-api-types package related to the raw command data accepted by Discord? In that case the return type of toJSON could be changed to this type and the create (set, etc...`) djs' method could also accept it as parameter. I see that it works as expected if I ignore the ts error so the source code is already compatible (or maybe not everything is supported?)

vladfrangu commented 3 years ago

I see that it works as expected if I ignore the ts error so the source code is already compatible (or maybe not everything is supported?)

It's """compatible""", default_permissions won't be respected by d.js right now 😓

suneettipirneni commented 3 years ago

So I may be missing something but there is no dedicated client-side type for application command data in discord-api-types. APIApplicationCommand represents command data sent back from the server (hence it requires and id and applicationId). I think the first step would be adding a client-side application command type to discord-api-types.

vladfrangu commented 3 years ago

Sure there is. RESTPostAPIApplicationCommandData or something aching to that

suneettipirneni commented 3 years ago

Alright, disregard my last comment

mahyarmirrashed commented 3 years ago

Any update on this issue?

Khasms commented 2 years ago

Fix got merged in #34.

MarcusOtter commented 2 years ago

FYI I couldn't figure out how to solve this without ReturnType<SlashCommandBuilder["toJSON"]>

It's the options property that's causing issues. Here's a few things I tried, hopefully this helps in debugging/understand the issue:

Click to see code and errors for options: APIApplicationCommandOption[];
import { SlashCommandBuilder } from "@discordjs/builders";
import { APIApplicationCommandOption } from "discord-api-types/payloads/v9";
...
async getInfo():
    Promise<{
        name: string;
        description: string;
        options: APIApplicationCommandOption[];
        default_permission: boolean | undefined;
    }> {
    return new SlashCommandBuilder()
        .setName("ping")
        .setDescription("Replies with pong")
        .toJSON();
},
Error:
Type 'ApplicationCommandOptionType.String' is not assignable to type 'ApplicationCommandOptionType.String | ApplicationCommandOptionType.Integer | ApplicationCommandOptionType.Number'.
Click to see code and errors for options: RESTPostAPIApplicationCommandsJSONBody[];
import { SlashCommandBuilder } from "@discordjs/builders";
import { RESTPostAPIApplicationCommandsJSONBody } from "discord-api-types";
...
async getInfo():
    Promise<{
        name: string;
        description: string;
        options: RESTPostAPIApplicationCommandsJSONBody[];
        default_permission: boolean | undefined;
    }> {
    return new SlashCommandBuilder()
        .setName("ping")
        .setDescription("Replies with pong")
        .toJSON();
},
Error:
Type 'ApplicationCommandOptionType.String' is not assignable to type 'ApplicationCommandType.ChatInput | undefined'

Tried a handful of other types that I saw being thrown around but couldn't find anything that worked. Would love to get any pointers what type it should really be (and most importantly, how I was supposed to figure that out).

I am using:

I don't mean to sound rude, but the developer experience with DJS types haven't been great so far, it feels like it should be easier than this image

Let me know if I should open another issue for this. Seemed like it was relevant to this one though.

suneettipirneni commented 2 years ago

FYI I couldn't figure out how to solve this without ReturnType<SlashCommandBuilder["toJSON"]>

It's the options property that's causing issues. Here's a few things I tried, hopefully this helps in debugging/understand the issue:

Click to see code and errors for options: APIApplicationCommandOption[];

import { SlashCommandBuilder } from "@discordjs/builders";
import { APIApplicationCommandOption } from "discord-api-types/payloads/v9";
...
async getInfo():
  Promise<{
      name: string;
      description: string;
      options: APIApplicationCommandOption[];
      default_permission: boolean | undefined;
  }> {
  return new SlashCommandBuilder()
      .setName("ping")
      .setDescription("Replies with pong")
      .toJSON();
},

Error: Type 'ApplicationCommandOptionType.String' is not assignable to type 'ApplicationCommandOptionType.String | ApplicationCommandOptionType.Integer | ApplicationCommandOptionType.Number'. Click to see code and errors for options: RESTPostAPIApplicationCommandsJSONBody[];

import { SlashCommandBuilder } from "@discordjs/builders";
import { RESTPostAPIApplicationCommandsJSONBody } from "discord-api-types";
...
async getInfo():
  Promise<{
      name: string;
      description: string;
      options: RESTPostAPIApplicationCommandsJSONBody[];
      default_permission: boolean | undefined;
  }> {
  return new SlashCommandBuilder()
      .setName("ping")
      .setDescription("Replies with pong")
      .toJSON();
},

Error: Type 'ApplicationCommandOptionType.String' is not assignable to type 'ApplicationCommandType.ChatInput | undefined' Tried a handful of other types that I saw being thrown around but couldn't find anything that worked. Would love to get any pointers what type it should really be (and most importantly, how I was supposed to figure that out).

I am using:

  • discord.js: 13.1.0
  • discord-api-types: 0.23.1
  • @discordjs/builders: 0.6.0

I don't mean to sound rude, but the developer experience with DJS types haven't been great so far, it feels like it should be easier than this image

Let me know if I should open another issue for this. Seemed like it was relevant to this one though.

Have you tried setting the return type of your function to Promise<RESTPostAPIApplicationCommandsJSONBody>?

MarcusOtter commented 2 years ago

Err actually I see now that the fix was merged 22 days ago but the version I'm on (0.6.0) was released 26 days ago. Guess I'm waiting for the next version?

MarcusOtter commented 2 years ago

@suneettipirneni Yep, my message shows both the code and the error for RESTPostAPIApplicationCommandsJSONBody. Click the arrows with that type

suneettipirneni commented 2 years ago

@suneettipirneni Yep, my message shows both the code and the error for RESTPostAPIApplicationCommandsJSONBody. Click the arrows with that type

Yes but that's incorrect, the command itself should be represented by RESTPostAPIApplicationCommandsJSONBody, not the options. I'm saying to change the entire:

Promise<{
    name: string;
    description: string;
    options: RESTPostAPIApplicationCommandsJSONBody[];
    default_permission: boolean | undefined;
}>

to

Promise<RESTPostAPIApplicationCommandsJSONBody>
MarcusOtter commented 2 years ago

Ah gotcha, sorry. Same problem though I'm afraid

Type 'ApplicationCommandOptionType.String' is not assignable to type 'ApplicationCommandOptionType.String | ApplicationCommandOptionType.Integer | ApplicationCommandOptionType.Number'
suneettipirneni commented 2 years ago

Ah gotcha, sorry. Same problem though I'm afraid

Type 'ApplicationCommandOptionType.String' is not assignable to type 'ApplicationCommandOptionType.String | ApplicationCommandOptionType.Integer | ApplicationCommandOptionType.Number'

Ok yeah I can reproduce this on the latest release, however the most up to date code works with this. I would just augment the module return type for now in a declaration file, until the release is made.

MarcusOtter commented 2 years ago

Thanks!

mahyarmirrashed commented 2 years ago

Sure there is. RESTPostAPIApplicationCommandData or something aching to that

This now fails in the latest version of discord-api-types (0.23.1). However, for 0.22.0, it still works.