#NonNullable utility type
63 messages · Page 1 of 1 (latest)
- Consider reading #how-to-get-help to improve your question!
- Explain what exactly your issue is.
- Post the full error stack trace, not just the top part!
- Show your code!
- Issue solved? Press the button!
For anyone else reading and wanting context: #djs-help-v14 message
I suggest giving this a decent look at first so you know what I'm actually talking about
https://www.typescriptlang.org/docs/handbook/utility-types.html#nonnullabletype
makes a lot of sense
Right, so you'd want to make an interface that extends the d.js ChatInputCommandinteraction
And in that interface, you define a channel property, and the type of that property is the NonNullable type of the ChatInputCommandInteraction.channel
All you're doing in this process is replacing the type of the channel property with exactly what it is, but excluding null
import type { ChatInputCommandInteraction } from "discord.js";
export interface ExtendedChatInputCommandInteraction extends ChatInputCommandInteraction {
channel: NonNullable<ChatInputCommandInteraction.channel>
}
like this?
Just about, yea. I'd add the CacheType enum generic (probably "cached" for you) there as well if needed
what will that do
Ensure that some properties of the interaction are cached. Of course, this is useless if you don't have your runtime checks beforehand in your command handler (e.g. inCachedGuild() like some have suggested to you)
ah so adding "cached" then doing the caching checks will be good too?
Yes. That makes you dialed both on the type level and runtime level
how would i do this?
Sorry - just realized - not enum, generic
interface ... extends ChatInputCommandInteraction<"cached">
This is what I did for my project, if you'd like a - in my opinion - good reference
Can you show what you typed channel as behind that hover window?
channel: NonNullable<ChatInputCommandInteraction["channel"]>
Yea, you forgot to add the <"cached"> generic to there as well
ohhh
that fixes everything, so i just do the same thing for other commands if it's not a chat input command? e.g. context menus
You could, assuming you do your proper runtime checking beforehand there as well
okay can you remind me of the checks i must do
Well, moreless just as what you detailed in #djs-help-v14 - checking if interaction.channel is null
and checking interaction.inCachedGuild()?
Right, yea, that for member/guild-related data for the associated interaction
alr
what do you recommend i name my ExtendedChatInputCommandInteraction
Really up to you. I just prefix my interaction/client extensions with a T for the first letter of my username to denote that I made it, followed by whatever it is, TInteraction in this case
Although I don't fully suggest using that naming scheme for your slash command interaction extension, as {prefix}Interaction is a bit vague since there's multiple different kinds of interactions
tysm man you've been a MASSIVE help, sorry about being difficult
also i moved all my typings to typings.ts, do you recommend .ts or .d.ts?
That's something I don't have full knowledge on, so if you want a solid answer, I'd wait for if someone else more knowledgeable in TS would want to chime in
alr
oh one last thing
Is this run() function part of a class?
ohhh i see
Looks like it
hmmmm now im getting this
if(interaction.isChatInputCommand()) {
if(!interaction.channel || !interaction.inCachedGuild()) return;
command.run(interaction);
}
Yea, I think that's a shortcoming of that, as I can't think of an easy and safe way to have them play nicely if you're using classes for your commands
im just doing this ```ts
export interface Command {
name?: string; // Optional as not explicitly given in command files
description: string;
type: ApplicationCommandType;
options?: ApplicationCommandOptionData[];
run: (interaction: ECICInteraction) => Promise<void>;
autocomplete?: (interaction: AutocompleteInteraction) => Promise<void>;
}
Yea you might have to make some compromises, not totally sure with that one. It works for me because my command file types are cut off when they exit the command files into my command handler. You seem to be constraining your command files to that Command interface which is what your command files also use
are cut off when they exit the command files
wdym by this? do you have a ref
I don't constrain my command file exports to an Interface like you do
ah
I'm just exporting them as they are
Which does work for me, however can be a bit risky during runtime if you don't format your command file properly and don't realize
yeah
doing command.run(interaction as ECICInteraction); fixed it
is that a good idea?
Well, with you doing your runtime checking above it, I don't really see a reason for it to not be safe. Type casting should really be a last resort, and it does seem like this might be a case where you would otherwise be stuck in a tight corner with type errors. I can't think of a better way to do this, so it seems to me like that'd be your best bet there
alr tysm
its 5am so im gonna sleep now aha
Have a good one
you too<3
Make a typeguard yourself
function isECICInteraction(interaction: Interaction): interaction is ECICInteraction {
return interaction.isChatInputCommand() && interaction.inCachedGuild() && interaction.channel !== null;
}
Better than an explicit cast, since it couples your runtime checks and the type change so you won‘t cast without checks