Rhys - Is there a way to use preconditions to remo...

Is there a way to use preconditions to remove redundant if checks? For example:
@ApplyOptions<Command.Options>({
name: "channel-settings",
preconditions: ["GuildOnly"]})
export class UserCommand extends Command {

// slash command
public async chatInputRun(interaction: Command.ChatInputInteraction) {
const channel_settings = await this.container.answer_overflow.channel_settings.get({
where: {
channel_id: interaction.channelId,
},
});
// Problem is here, precondition says this only runs in a guild
const guild = interaction.guild;
}
}
@ApplyOptions<Command.Options>({
name: "channel-settings",
preconditions: ["GuildOnly"]})
export class UserCommand extends Command {

// slash command
public async chatInputRun(interaction: Command.ChatInputInteraction) {
const channel_settings = await this.container.answer_overflow.channel_settings.get({
where: {
channel_id: interaction.channelId,
},
});
// Problem is here, precondition says this only runs in a guild
const guild = interaction.guild;
}
}
The expectation there is that guild would be defined, but its type is Guild | None so I have to add if checks to it to make typescript happy Two alternatives I can think of are: 1. Making something like a 'GuildCommand' class which has a function that takes guild as a parameter, and then extending that class with the other commands something along the lines of
export abstract class GuildCommand{

public abstract guildCommandRun(interaction: Command.ChatInputInteraction, guild: Guild, ...);


public async chatInputRun(interaction: Command.ChatInputInteraction) {
if(!interaction.guild)
{
respond('no guild found';
return;
}
await guildCommandRun(interaction, guild, ...)

}
export abstract class GuildCommand{

public abstract guildCommandRun(interaction: Command.ChatInputInteraction, guild: Guild, ...);


public async chatInputRun(interaction: Command.ChatInputInteraction) {
if(!interaction.guild)
{
respond('no guild found';
return;
}
await guildCommandRun(interaction, guild, ...)

}
2. Asserting the type i.e
const guild = interaction.guild as Guild;
const guild = interaction.guild as Guild;
but then that's not great as I'm losing the typesafety of typescript and ignoring the warning I'm currently leaning towards approach #1, with treating preconditions more as a runtime check thing for permissions & cooldowns Looking at the docs again it actually looks like the validation in supposed to happen in the parse method, so I suppose you could put the conditional checks there, although then from my understanding you don't get to give error messages to the user
3 Replies
Rhys
RhysOP3y ago
Going to keep playing with this but found a solution that works decently ButtonBaseHandler:
public async getParseData(interaction: ButtonInteraction) {
if (!this.checkIfButtonIDMatches(interaction)) return null;
return {};
}

public async getParseData(interaction: ButtonInteraction) {
if (!this.checkIfButtonIDMatches(interaction)) return null;
return {};
}

GuildTextChannelButtonHandler
public override async parse(interaction: ButtonInteraction) {
const data = await super.parse(interaction);
if (data.isNone()) return this.none();
const interaction_with_target_channel = addTargetChannelToInteraction(
interaction,
data.unwrap()
);
return this.some(interaction_with_target_channel);
}
public override async parse(interaction: ButtonInteraction) {
const data = await super.parse(interaction);
if (data.isNone()) return this.none();
const interaction_with_target_channel = addTargetChannelToInteraction(
interaction,
data.unwrap()
);
return this.some(interaction_with_target_channel);
}
This is layer 1, it now sets up having a parent channel in child classes ChannelSettingsButtonHandler
public override async parse(interaction: ButtonInteraction) {
const some = await super.parse(interaction);
if (some.isNone()) return this.none();
const data = some.unwrap();
const with_channel_data = await addChannelSettingsParseDataToInteraction(
data.parent_channel,
data
);
return this.some(with_channel_data);
}
public override async parse(interaction: ButtonInteraction) {
const some = await super.parse(interaction);
if (some.isNone()) return this.none();
const data = some.unwrap();
const with_channel_data = await addChannelSettingsParseDataToInteraction(
data.parent_channel,
data
);
return this.some(with_channel_data);
}
edit: realized this was for a different problem than the one above with button setups, whoopsie So each layer overrides get parse data to extract the data it needs, then the very bottom layer has to call what is in the parse function to have types available throughout it
Seren_Modz 21
Seren_Modz 213y ago
u can use generics it works on other interaction types that have the cache type generic
async chatInputRun(interaction: Command.ChatInputInteraction<"cached">) {
// interaction.guild will no longer be nullable
}
async chatInputRun(interaction: Command.ChatInputInteraction<"cached">) {
// interaction.guild will no longer be nullable
}
i personally don't see any issue with doing this because the precondition already prevents the command if there is no guild
Rhys
RhysOP3y ago
Ah thanks that's helpful, I think that's what I'm looking for

Did you find this page helpful?