fix(bot)!: fix type errors when using commandOptionsParser (#3994)

* Fix type errors when using commandOptionsParser

* remove export from TransformProperty

* use TransformProperty in InteractionResolvedData

* Fix CI

* Remove the union on GetErrorWhenUndesired
This commit is contained in:
Fleny
2024-11-23 21:50:16 +01:00
committed by GitHub
parent 078036f626
commit cdf0be41b6
2 changed files with 70 additions and 27 deletions

View File

@@ -1,52 +1,85 @@
import { ApplicationCommandOptionTypes } from '@discordeno/types'
import type { Attachment, Channel, Interaction, InteractionDataOption, Member, Role, User } from './index.js'
import type {
Attachment,
Channel,
DesiredPropertiesBehavior,
Interaction,
InteractionDataOption,
Member,
Role,
SetupDesiredProps,
TransformProperty,
TransformersDesiredProperties,
User,
WithAtLeast,
} from './index.js'
export function commandOptionsParser<
TProps extends WithAtLeast<TransformersDesiredProperties, { interaction: { data: true } }>,
TBehavior extends DesiredPropertiesBehavior,
>(__interaction: SetupDesiredProps<Interaction, TProps, TBehavior>, options?: InteractionDataOption[]): ParsedInteractionOption<TProps, TBehavior> {
// This is necessary as typescript gets really confused when using __interaction alone, as it will say that 'data' does not exist despite it surely exist since we have the WithAtLeast
const interaction = __interaction as SetupDesiredProps<
Interaction,
WithAtLeast<TransformersDesiredProperties, { interaction: { data: true } }>,
DesiredPropertiesBehavior.RemoveKey
>
export function commandOptionsParser(interaction: Interaction, options?: InteractionDataOption[]): ParsedInteractionOption {
if (!interaction.data) return {}
if (!options) options = interaction.data.options ?? []
const args: ParsedInteractionOption = {}
const args: ParsedInteractionOption<TProps, TBehavior> = {}
for (const option of options) {
switch (option.type) {
case ApplicationCommandOptionTypes.SubCommandGroup:
case ApplicationCommandOptionTypes.SubCommand:
args[option.name] = commandOptionsParser(interaction, option.options)
args[option.name] = commandOptionsParser(interaction, option.options) as InteractionResolvedData<TProps, TBehavior>
break
case ApplicationCommandOptionTypes.Channel:
args[option.name] = interaction.data.resolved?.channels?.get(BigInt(option.value!)) as InteractionResolvedChannel
args[option.name] = interaction.data.resolved?.channels?.get(BigInt(option.value!)) as InteractionResolvedData<TProps, TBehavior>
break
case ApplicationCommandOptionTypes.Role:
args[option.name] = interaction.data.resolved?.roles?.get(BigInt(option.value!)) as Role
args[option.name] = interaction.data.resolved?.roles?.get(BigInt(option.value!)) as InteractionResolvedData<TProps, TBehavior>
break
case ApplicationCommandOptionTypes.User:
args[option.name] = {
user: interaction.data.resolved?.users?.get(BigInt(option.value!)) as User,
member: interaction.data.resolved?.members?.get(BigInt(option.value!)) as InteractionResolvedMember,
user: interaction.data.resolved?.users?.get(BigInt(option.value!)) as InteractionResolvedData<TProps, TBehavior>,
member: interaction.data.resolved?.members?.get(BigInt(option.value!)) as InteractionResolvedData<TProps, TBehavior>,
}
break
case ApplicationCommandOptionTypes.Attachment:
args[option.name] = interaction.data.resolved?.attachments?.get(BigInt(option.value!)) as Attachment
args[option.name] = interaction.data.resolved?.attachments?.get(BigInt(option.value!)) as InteractionResolvedData<TProps, TBehavior>
break
case ApplicationCommandOptionTypes.Mentionable:
// Mentionable are roles or users
args[option.name] = (interaction.data.resolved?.roles?.get(BigInt(option.value!)) as Role) ?? {
user: interaction.data.resolved?.users?.get(BigInt(option.value!)) as User,
member: interaction.data.resolved?.members?.get(BigInt(option.value!)) as InteractionResolvedMember,
args[option.name] = (interaction.data.resolved?.roles?.get(BigInt(option.value!)) as ParsedInteractionOption<TProps, TBehavior>[string]) ?? {
user: interaction.data.resolved?.users?.get(BigInt(option.value!)) as InteractionResolvedData<TProps, TBehavior>,
member: interaction.data.resolved?.members?.get(BigInt(option.value!)) as InteractionResolvedData<TProps, TBehavior>,
}
break
default:
args[option.name] = option.value as ParsedInteractionOption[string]
args[option.name] = option.value as InteractionResolvedData<TProps, TBehavior>
}
}
return args
}
export interface ParsedInteractionOption {
[key: string]: string | number | boolean | InteractionResolvedUser | InteractionResolvedChannel | Role | Attachment | ParsedInteractionOption
export interface ParsedInteractionOption<TProps extends TransformersDesiredProperties, TBehavior extends DesiredPropertiesBehavior> {
[key: string]: InteractionResolvedData<TProps, TBehavior>
}
export type InteractionResolvedData<TProps extends TransformersDesiredProperties, TBehavior extends DesiredPropertiesBehavior> =
| string
| number
| boolean
| TransformProperty<InteractionResolvedUser, TProps, TBehavior>
| TransformProperty<InteractionResolvedChannel, TProps, TBehavior>
| TransformProperty<Role, TProps, TBehavior>
| TransformProperty<Attachment, TProps, TBehavior>
| ParsedInteractionOption<TProps, TBehavior>
export interface InteractionResolvedUser {
user: User
member: InteractionResolvedMember

View File

@@ -729,6 +729,10 @@ type Complete<TObj, TDefault> = {
[K in keyof TObj]-?: undefined extends TObj[K] ? TDefault : Exclude<TObj[K], undefined>
}
export type WithAtLeast<T extends TransformersDesiredProperties, AtLeast extends RecursivePartial<TransformersDesiredProperties>> = T & {
[K in keyof T]: K extends keyof AtLeast ? Complete<AtLeast[K], false> & T[K] : T[K]
}
type JoinTuple<T extends string[], TDelimiter extends string> = T extends readonly [infer F extends string, ...infer R extends string[]]
? R['length'] extends 0
? F
@@ -811,30 +815,36 @@ type GetErrorWhenUndesired<
TransformersDesiredPropertiesMetadata[KeyByValue<TransformersObjects, T>]['dependencies'],
TProps[KeyByValue<TransformersObjects, T>]
>,
> = TIsDesired extends true ? TransformNestedProps<T[Key], TProps, TBehavior> : TIsDesired
> = TIsDesired extends true ? TransformProperty<T[Key], TProps, TBehavior> : TIsDesired
type IsObject<T> = T extends object ? (T extends Function ? false : true) : false
// If the object is a transformed object, a collection of transformed object or an array of transformed objects we need to apply the desired props to them as well
type TransformNestedProps<
export type TransformProperty<
T,
TProps extends TransformersDesiredProperties,
TBehavior extends DesiredPropertiesBehavior,
> = T extends TransformersObjects[keyof TransformersObjects] // is T a transformed object?
? // Yes, apply the desired props
SetupDesiredProps<T, TProps, TBehavior>
: // No, is it a collection of transformed objects?
T extends Collection<infer U, infer UObj extends TransformersObjects[keyof TransformersObjects]>
? // Yes, apply the desired props
Collection<U, SetupDesiredProps<UObj, TProps, TBehavior>>
: // No, is it an array of transformed objects?
T extends Array<infer U extends TransformersObjects[keyof TransformersObjects]>
: // No, is it a collection?
T extends Collection<infer U, infer UObj>
? // Yes, check for nested proprieties
Collection<U, TransformProperty<UObj, TProps, TBehavior>>
: // No, is it an array?
T extends Array<infer U>
? // Yes, apply the desired props
SetupDesiredProps<U, TProps, TBehavior>[]
TransformProperty<U, TProps, TBehavior>[]
: // No, is it a Bot?
T extends Bot
? // Yes, return a bot with the correct set of props & behavior
Bot<TProps, TBehavior>
: // No, this is a normal value such as string / bigint / number
T
: // No, is this a generic object? If so we need to ensure nested inside there aren't transformed objects
IsObject<T> extends true
? // Yes, check of nested proprieties
{ [K in keyof T]: TransformProperty<T[K], TProps, TBehavior> }
: // No, this is a normal value such as string / bigint / number
T
export type SetupDesiredProps<
T extends TransformersObjects[keyof TransformersObjects],
@@ -847,7 +857,7 @@ export type SetupDesiredProps<
: Key]: // When the behavior is to change the type we use the GetErrorWhenUndesired type helper else apply the desired props to the key and return
TBehavior extends DesiredPropertiesBehavior.ChangeType
? GetErrorWhenUndesired<Key, T, TProps, TBehavior>
: TransformNestedProps<T[Key], TProps, TBehavior>
: TransformProperty<T[Key], TProps, TBehavior>
}
export type TransformersDesiredProperties = {