Общий класс TypeScript для команд DiscordJS

В настоящее время я работаю над ботом Discord, я новичок в TypeScript, и мне нужна помощь с моим классом команд...

Это мой текущий класс:

export class Command {
  constructor(
    public options: {
      ...
      data: ApplicationCommandData & {
        type: ApplicationCommandType;
        contexts?: Context[];
        integration_types?: IntegrationTypes[];
      };
      execute: (options: { client: DiscordClient; interaction: CommandInteraction }) => any;
      ...
    }
  ) {}
}

Вот как его использовать:

export default new Command({
  data: {
    name: 'ping',
    description: 'Replies with Pong!',
    type: ApplicationCommandType.ChatInput,
    contexts: [Context.GUILD, Context.BOT_DM, Context.PRIVATE_CHANNEL],
    integration_types: [IntegrationTypes.GUILD_INSTALL, IntegrationTypes.USER_INSTALL],
  },
  execute({ interaction}) {
    interaction.reply({ content: 'Pong!', ephemeral: true });
  },
});

Проблема в том, что независимо от типа (User, Message или ChatInput) команды, взаимодействие всегда будет просто базовым CommandInteraction, и из нее невозможно получить строковые параметры (interaction.options.getString()). Мне пришлось бы поставить if (!interaction.isChatInputCommand()) return; вверху каждой ChatInputCommand, которая использует строковые параметры.

Теперь мне нужна помощь в создании универсального класса (если возможно) для решения этой проблемы. Я хочу, чтобы тип моего класса/команды определял тип взаимодействия функции выполнения.

Вот грубый (не работающий) пример того, что я имею в виду:

export class Command<Type> {
  constructor(
    public options: {
      ...
      data: ApplicationCommandData & {
        type: Type;
        contexts?: Context[];
        integration_types?: IntegrationTypes[];
      };
      execute: (options: { client: DiscordClient; interaction: interactions[type] }) => any;
      ...
    }
  ) {}
}

Я хочу, чтобы тип был взят из свойства command.options.data.type и использовался для прохождения через объект/массив взаимодействий, чтобы получить соответствующее взаимодействие для типа команды!

Пожалуйста, дайте мне знать, если это возможно. В противном случае мне просто придется сделать по 3 класса для каждого типа команды (User, Message, ChatInput)...

Я перепробовал много разных вещей, но в итоге не нашел решения.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
86
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Решил эту проблему с помощью

Это мой новый класс:

import {
  ApplicationCommandType,
  AutocompleteInteraction,
  ChatInputCommandInteraction,
  MessageContextMenuCommandInteraction,
  UserContextMenuCommandInteraction,
  type RESTPostAPIApplicationCommandsJSONBody,
} from 'discord.js';
import { DiscordClient } from './client';

export enum Contexts {
  GUILD = 0,
  BOT_DM = 1,
  PRIVATE_CHANNEL = 2,
}

export enum IntegrationTypes {
  GUILD_INSTALL = 0,
  USER_INSTALL = 1,
}

type InteractionType<T extends ApplicationCommandType> = T extends ApplicationCommandType.ChatInput
  ? ChatInputCommandInteraction
  : T extends ApplicationCommandType.Message
  ? MessageContextMenuCommandInteraction
  : T extends ApplicationCommandType.User
  ? UserContextMenuCommandInteraction
  : never;

export class Command<T extends ApplicationCommandType = ApplicationCommandType.ChatInput> {
  constructor(
    public options: {
      developerOnly?: boolean; // If command is for developer only, it cannot be used by anyone else
      cooldown?: number; // Cooldown between command executes per user (in milliseconds)
      data: RESTPostAPIApplicationCommandsJSONBody & {
        type: T;
        contexts?: Contexts[];
        integration_types?: IntegrationTypes[];
      };
      autocomplete?: (options: { client: DiscordClient; interaction: AutocompleteInteraction }) => any;
      execute: (options: { client: DiscordClient; interaction: InteractionType<T> }) => any;
    }
  ) {}
}

И это автоматически дает мне правильный тип взаимодействия для моих взаимодействий в зависимости от типа команды.

Вот пример ChatInputCommand и UserContextMenuCommand:

import { ActionRowBuilder, ApplicationCommandType, ButtonBuilder, ButtonStyle, Colors, EmbedBuilder } from 'discord.js';

import { Command, Contexts, IntegrationTypes } from 'classes/command';

export default new Command({
  data: {
    name: 'ping',
    description: 'Replies with Pong!',
    type: ApplicationCommandType.ChatInput,
    contexts: [Contexts.GUILD, Contexts.BOT_DM, Contexts.PRIVATE_CHANNEL],
    integration_types: [IntegrationTypes.GUILD_INSTALL, IntegrationTypes.USER_INSTALL],
  },
  async execute({ interaction, client }) {
    const sent = await interaction.reply({ content: 'Pinging...', fetchReply: true });

    await interaction.editReply({
      content: '',
      embeds: [
        new EmbedBuilder()
          .setColor(Colors.Blurple)
          .setTitle(i18next.t('Pong!', { lng }))
          .addFields(
            { name: 'Websocket Hearbeat', value: `${client.ws.ping}` },
            { name: 'Roundtrip Latency', value: `${sent.createdTimestamp - interaction.createdTimestamp}ms` }
          ),
      ],
    });
  },
});
import { ApplicationCommandType, Colors, EmbedBuilder } from 'discord.js';

import { Command, Contexts, IntegrationTypes } from 'classes/command';

export default new Command({
  data: {
    name: 'Avatar & Banner',
    type: ApplicationCommandType.User,
    contexts: [Contexts.GUILD, Contexts.BOT_DM, Contexts.PRIVATE_CHANNEL],
    integration_types: [IntegrationTypes.GUILD_INSTALL, IntegrationTypes.USER_INSTALL],
  },
  async execute({ interaction, client }) {
    await interaction.deferReply({ ephemeral: true });

    try {
      const user = await client.users.fetch(interaction.targetId, { force: true });
      if (!user) return interaction.editReply('Could not find user');

      const member = await interaction.guild?.members.fetch(user.id);

      const embeds: EmbedBuilder[] = [
        new EmbedBuilder()
          .setImage(user.displayAvatarURL({ size: 4096 })),
      ];
      if (user.banner)
        embeds.push(
          new EmbedBuilder()
            .setImage(user.bannerURL({ size: 4096 })!)
        );
      if (member && member.avatar)
        embeds.push(
          new EmbedBuilder()
            .setImage(member.displayAvatarURL({ size: 4096 }))
        );

      interaction.editReply({ embeds });
    } catch (err) {
      interaction.editReply('Something went wrong');
    }
  },
});

Дополнительную информацию об исходном коде см. проверьте мой репозиторий GitHub: https://github.com/CuteNikki/discord-bot

Другие вопросы по теме