#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
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