#Reduce with initial keys not directly related to current value

83 messages ยท Page 1 of 1 (latest)

steady gazelleBOT
#
Daniell#4062

Preview:```ts
import {} from "discord-api-types"
import {
ApplicationCommandOptionData,
CommandInteractionOption,
ApplicationCommandOptionType,
User,
Channel,
Role,
Attachment,
} from "discord.js"

export type ApplicationCommandOptionTypeValues<
T extends ApplicationCommandOptionData[]

...```

split nova
#

Could use some help to solve the type error(s) in a clean way

uncut edge
#

not sure there's a safe way to solve it

#

but here's what i think is the least bad way to solve it:

steady gazelleBOT
#
n_n#2622

Preview:```ts
...
ApplicationCommandOptionType.Attachment
) {
previousValue[option.name] = option.attachment
}

return previousValue

}, {} as Partial<Record<string, ApplicationCommandOptionTypeValues<T>[ApplicationCommandOptionType]>>) as InferCommandOptions<T>
...```

uncut edge
#

you widen it to have a string index signature, and let any value be assignable to it

#

which is... not quite ideal

#

but it's a lot better than nothing imo

#

also i changed the [].some() to option.type === A || option.type === B

#

since [].some() doesn't narrow option.type

#

not that it matters here, so it's more of a personal preference

split nova
#

Thanks! Is the any 100% needed? No passing in generic hack or more accurate assert?

uncut edge
#

you could replace it with as unknown as T[number];

#

but as unknown as T is just as unsafe (read: 100% unsafe)

#

the inferred type is InferCommandOptions<ApplicationCommandOptionData[]>...

#

which may be correct tbh

#
  [ApplicationCommandOptionType.Subcommand]: T[number];
  [ApplicationCommandOptionType.SubcommandGroup]: T[number];
#

this does look a bit suspicious

#

where does the T from T extends ApplicationCommandOptionData[] even come from btw

split nova
#

[ApplicationCommandOptionType.Subcommand]: T; is probably wrong though and should be something like InferCommandOptions<T[number]> or something

#

Or well it should be whatever transform(option.options ? [...option.options] : []) returns, not sure if I was correct in that case

split nova
uncut edge
#

uhm

#

ok so the issue is that Subcommand has a different list of options, right?

#

and so:

  [ApplicationCommandOptionType.Subcommand]: T[number];
  [ApplicationCommandOptionType.SubcommandGroup]: T[number];
#

i don't think this is correct

#

but i'm not sure you can even have a good, narrow type for these

split nova
potent zealotBOT
#
: T extends ApplicationCommandOptionType.SubcommandGroup
uncut edge
#

i think this is the correct solution:

steady gazelleBOT
#
n_n#2622

Preview:```ts
...
[ApplicationCommandOptionType.Subcommand]: InferCommandOptions<
ApplicationCommandOptionData[]

ApplicationCommandOptionData[]

[
...```

uncut edge
#

the error does go away, but that's because the types are wider

#

but, i don't think it's possible to have narrower types?

split nova
#

I think that's fine! In the end it's not possible to narrow anyway because the function should work with all commands and their different options

#

And the option object is typed anyway where it matters

#

Thanks

uncut edge
#

oh

#

i just saw

#
const transform = <T extends ApplicationCommandOptionData[]>(
  options: ReadonlyArray<CommandInteractionOption<"cached">>
) 
#

there is nowhere to infer T from

#

and so the generic does nothing here

split nova
uncut edge
split nova
#

Ohh okay I'll get rid of it then

uncut edge
#

yeah idk if there's a nice solution

#

because interaction.options isn't generic

split nova
#

Yup

#

What's up with the bigint error though ๐Ÿค”

uncut edge
#

wait where

split nova
#

In transform

uncut edge
#

there's an error?

split nova
#

Oh not anymore, saw a red underline on mobile

uncut edge
#

yeah weird stuff happens when it's still loading types

#

anyway fwiw i just have a massive nested switch-case for commands

#

and just do unsafe casts

split nova
#

Can I see your repo

uncut edge
#

it's not public tho

split nova
#

Ah

uncut edge
#
  • i use discordeno, not djs
#

but the idea is the same

split nova
#

Don't you prefer something like above?

#

Overall it work pretty good

uncut edge
#

it does, but it's too complicated for me

#
interface FooData {
    /** unix epoch */
    timestamp: number;
    foo: number;
    bar: number;
}
#
function getOpts<T>(obj: { options?: unknown[]; }): T {
    // deno-lint-ignore no-explicit-any
    return Object.fromEntries((obj.options ?? []).map((opt: any) => [opt.name, opt.value])) as T;
}
#

this is so horribly unsafe

#

but hey, i get nice types and that's all i care about

#

you do have to make sure it stays in sync with your options

#

but realistically after the first few mistakes you start to remember to update things everywhere else

#

plus you'll catch it when testing anyway

split nova
#

I see, honestly I mainly made this to test my limits so I'm trying to avoid any and type all those complex patterns

uncut edge
split nova
#

Yea, that would have been easier

#

But now I have 0 any which is kind of satisfying

uncut edge
#

i guess

#

but do remember, just because you avoid any it doesn't mean it's any less unsafe

#

sometimes it's better to use any to make it obvious where you're abusing the type system

split nova
#

Yup I think I have a good feel where it should be used or there's no other option

uncut edge
#

also fwiw i think decorators are great for ux

uncut edge
split nova
#

I wish decorators would work outside classes :/