#NonNullable utility type

63 messages · Page 1 of 1 (latest)

wind hull
#

@warm knoll

ebon rockBOT
#
  • 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!
warm knoll
#

For anyone else reading and wanting context: #djs-help-v14 message

wind hull
#

makes a lot of sense

warm knoll
#

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

wind hull
#
import type { ChatInputCommandInteraction } from "discord.js";

export interface ExtendedChatInputCommandInteraction extends ChatInputCommandInteraction {
  channel: NonNullable<ChatInputCommandInteraction.channel>
}

like this?

warm knoll
#

Just about, yea. I'd add the CacheType enum generic (probably "cached" for you) there as well if needed

wind hull
#

what will that do

warm knoll
#

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)

wind hull
#

ah so adding "cached" then doing the caching checks will be good too?

warm knoll
#

Yes. That makes you dialed both on the type level and runtime level

warm knoll
#

Sorry - just realized - not enum, generic

#

interface ... extends ChatInputCommandInteraction<"cached">

wind hull
warm knoll
#

This is what I did for my project, if you'd like a - in my opinion - good reference

warm knoll
# wind hull

Can you show what you typed channel as behind that hover window?

wind hull
#

channel: NonNullable<ChatInputCommandInteraction["channel"]>

warm knoll
#

Yea, you forgot to add the <"cached"> generic to there as well

wind hull
#

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

warm knoll
#

You could, assuming you do your proper runtime checking beforehand there as well

wind hull
#

okay can you remind me of the checks i must do

warm knoll
#

Well, moreless just as what you detailed in #djs-help-v14 - checking if interaction.channel is null

wind hull
#

and checking interaction.inCachedGuild()?

warm knoll
#

Right, yea, that for member/guild-related data for the associated interaction

wind hull
#

alr

#

what do you recommend i name my ExtendedChatInputCommandInteraction

warm knoll
#

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

wind hull
#

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?

warm knoll
#

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

wind hull
#

alr

#

oh one last thing

warm knoll
#

Is this run() function part of a class?

wind hull
#

ohhh i see

warm knoll
#

Looks like it

wind hull
#

hmmmm now im getting this

#
if(interaction.isChatInputCommand()) {
   if(!interaction.channel || !interaction.inCachedGuild()) return;

   command.run(interaction);
}
warm knoll
#

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

wind hull
#

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>;
}

warm knoll
#

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

wind hull
#

are cut off when they exit the command files
wdym by this? do you have a ref

warm knoll
#

I don't constrain my command file exports to an Interface like you do

wind hull
#

ah

warm knoll
#

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

wind hull
#

yeah

#

doing command.run(interaction as ECICInteraction); fixed it

#

is that a good idea?

warm knoll
#

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

wind hull
#

alr tysm

#

its 5am so im gonna sleep now aha

warm knoll
#

Have a good one

wind hull
#

you too<3

unreal obsidian
# wind hull is that a good idea?

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