我目前正在开发一个 Discord Bot,我对 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
)...
我尝试了很多不同的东西,但最终找不到解决方案。
在 ChatGPT 的帮助下解决了这个问题
这是我的新班级:
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