Saltearse al contenido

Entendiendo 'declare module'

Los siguientes códigos puedes utilizarlos dentro de cualquier archivo TypeScript de tu proyecto. Lo recomendable es colocar un único declare module 'seyfert' en el archivo principal src/index.ts que contenga todo lo necesario para tu bot.

Clientes

Seyfert ofrece varios tipos de cliente para instanciar tu bot, lo que podría generar confusión al referenciar el cliente en distintas partes de tu código. Para evitar esto, puedes indicarle a TypeScript qué tipo de cliente estás utilizando. Asegúrate de elegir solo una de las siguientes tres implementaciones:

import type {
type ParseClient<T extends BaseClient> = T
ParseClient
,
class Client<Ready extends boolean = boolean>
Client
,
class HttpClient
HttpClient
,
class WorkerClient<Ready extends boolean = boolean>
WorkerClient
} from 'seyfert';
declare module 'seyfert' {
interface
interface UsingClient
UsingClient
extends
type ParseClient<T extends BaseClient> = T
ParseClient
<
class Client<Ready extends boolean = boolean>
Client
<true>> { }
interface
interface UsingClient
UsingClient
extends
type ParseClient<T extends BaseClient> = T
ParseClient
<
class HttpClient
HttpClient
> { }
interface
interface UsingClient
UsingClient
extends
type ParseClient<T extends BaseClient> = T
ParseClient
<
class WorkerClient<Ready extends boolean = boolean>
WorkerClient
<true>> { }
}

Intermediarios (Middlewares)

Para utilizar tus middlewares en todo el proyecto, es necesario nuevamente informar a TypeScript sobre su estructura y composición. Exporta todos los middlewares de tu código y proporciónaselos a Seyfert de la siguiente manera:

// Suponiendo que exportaste todos los middlewares de './middlewares';
import type * as allMiddlewares from './middlewares';
declare module 'seyfert' {
interface RegisteredMiddlewares extends ParseMiddlewares<typeof allMiddlewares> {}
}

Esto se aplica de manera similar a los middlewares globales, los cuales se ejecutan automáticamente en cada comando, incluso si no han sido especificados explícitamente en él.

// Suponiendo que exportaste todos los middlewares de './globalMiddlewares';
import type * as globalMiddlewares from './globalMiddlewares';
declare module 'seyfert' {
interface GlobalMetadata extends ParseMiddlewares<typeof globalMiddlewares> {}
}

Si aún no sabes qué es un middleware, puedes revisar sus casos de uso y estructura en su respectiva sección.

Idiomas

Para configurar correctamente los tipos para los idiomas, se recomienda establecer un idioma principal o base que siempre actualices. Así, todos los tipos se derivarán de este idioma, lo que facilitará mantener el resto de las traducciones al día.

// Suponiendo que tu lenguaje base (principal) está en './langs/en';
import type * as defaultLang from './langs/en';
declare module 'seyfert' {
interface DefaultLocale extends ParseLocales<typeof defaultLang> {}
}

Si aún no sabías que Seyfert cuenta con un sistema de idiomas automático, te recomendamos visitar la sección dedicada a esto.

Contextos

A menudo necesitamos extender los contextos para agregar propiedades o métodos útiles, lo que también requiere actualizar los tipos.

Si has utilizado extendContext para esto, puedes utilizar el siguiente código para inferir el tipo que devuelve tu función y añadirlo al contexto:

import {
function extendContext<T extends {}>(cb: (interaction: Parameters<NonNullable<BaseClientOptions["context"]>>[0]) => T): (interaction: Parameters<NonNullable<BaseClientOptions["context"]>>[0]) => T

Extends the context of a command interaction.

@paramcb - The callback function to extend the context.

@returnsThe extended context.

@example const customContext = extendContext((interaction) => { return { owner: '123456789012345678', // Add your custom properties here }; });

extendContext
} from 'seyfert';
const
const context: (interaction: Parameters<NonNullable<BaseClientOptions["context"]>>[0]) => {
nutria: string;
}
context
=
extendContext<{
nutria: string;
}>(cb: (interaction: Parameters<NonNullable<BaseClientOptions["context"]>>[0]) => {
nutria: string;
}): (interaction: Parameters<NonNullable<BaseClientOptions["context"]>>[0]) => {
nutria: string;
}

Extends the context of a command interaction.

@paramcb - The callback function to extend the context.

@returnsThe extended context.

@example const customContext = extendContext((interaction) => { return { owner: '123456789012345678', // Add your custom properties here }; });

extendContext
((
ctx: ChatInputCommandInteraction<boolean> | UserCommandInteraction<boolean> | MessageCommandInteraction<boolean> | ComponentInteraction<...> | ModalSubmitInteraction<...> | EntryPointInteraction<...>
ctx
) => ({
nutria: string
nutria
: 'tierna' }));
declare module 'seyfert' {
interface
interface ExtendContext
ExtendContext
extends
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any

Obtain the return type of a function type

ReturnType
<typeof
const context: (interaction: Parameters<NonNullable<BaseClientOptions["context"]>>[0]) => {
nutria: string;
}
context
> {}
}

Si aún no sabías que con Seyfert puedes modificar y extender el contexto de forma sencilla, puedes revisar su respectiva sección.

Propiedades de comando

A menudo necesitamos categorizar algunos comandos, o simplemente ponerles un identificador para algo.

Para esto, podemos usar ExtraProps:

const
const client: Client<boolean>
client
= new
new Client<boolean>(options?: ClientOptions): Client<boolean>
Client
({
ClientOptions.commands?: {
defaults?: {
onRunError?: (context: MenuCommandContext<any, never> | CommandContext, error: unknown) => unknown;
onPermissionsFail?: Command["onPermissionsFail"];
onBotPermissionsFail?: (context: MenuCommandContext<any, never> | CommandContext, permissions: PermissionStrings) => unknown;
onInternalError?: (client: UsingClient, command: Command | SubCommand | ContextMenuCommand, error?: unknown) => unknown;
onMiddlewaresError?: (context: CommandContext | MenuCommandContext<any, never>, error: string) => unknown;
onOptionsError?: Command["onOptionsError"];
onAfterRun?: (context: CommandContext | MenuCommandContext<any, never>, error: unknown) => unknown;
props?: ExtraProps;
};
} & {
...;
}
commands
: {
defaults?: {
onRunError?: (context: MenuCommandContext<any, never> | CommandContext, error: unknown) => unknown;
... 6 more ...;
props?: ExtraProps;
}
defaults
: {
props: {
Error ts(2741) ― Property 'soloParaAdmins' is missing in type '{ categoria: string; }' but required in type 'ExtraProps'.
ExtraProps.categoria?: string
categoria
: 'none'
}
}
}
});
@
function Declare(declare: CommandDeclareOptions): <T extends {
new (...args: any[]): object;
}>(target: T) => {
new (...args: any[]): {
name: string;
nsfw: boolean | undefined;
props: ExtraProps | undefined;
contexts: InteractionContextType[];
integrationTypes: ApplicationIntegrationType[];
defaultMemberPermissions: bigint | undefined;
botPermissions: bigint | undefined;
description: string;
type: ApplicationCommandType;
guildId?: string[];
ignore?: IgnoreCommand;
aliases?: string[];
handler?: EntryPointCommandHandlerType;
};
} & T
Declare
({
name: string
name
: 'test',
description: string
description
: 'comando de prueba',
props: {}
Error ts(2741) ― Property 'soloParaAdmins' is missing in type '{}' but required in type 'ExtraProps'.
})
class
class Test
Test
extends
class Command
Command
{}
declare module 'seyfert' {
interface
interface ExtraProps
ExtraProps
{
ExtraProps.soloParaAdmins: boolean
soloParaAdmins
: boolean;
ExtraProps.deshabilitado?: true
deshabilitado
?: true;
ExtraProps.categoria?: string
categoria
?: string
}
}

Opciones internas

Como Seyfert admite diversas formas de operar, es necesario añadir tipos según lo requieran nuestras implementaciones. Para ello, existe InternalOptions, una interfaz diseñada para incluir propiedades que transformen los tipos de Seyfert en algo más completo.

declare module 'seyfert' {
interface
interface InternalOptions
InternalOptions
{
InternalOptions.withPrefix: true
withPrefix
: true; // o false
InternalOptions.asyncCache: false
asyncCache
: false; // o true
}
}

withPrefix

Establecer esta propiedad en true indica a Seyfert que el contexto puede incluir un mensaje o una interacción, siendo ambos opcionales. De forma predeterminada, .interaction siempre está presente en el contexto.

asyncCache

Establecer esta propiedad en true indica a Seyfert si la caché devolverá una promesa. Por defecto, Seyfert utiliza MemoryAdapter, una caché en RAM que no devuelve promesas, mientras que RedisAdapter sí lo hace.

Configuración

En Seyfert, puedes agregar más propiedades al archivo de configuración seyfert.config.mjs, independientemente de si estás utilizando la configuración http o bot. Esto se puede lograr utilizando ExtendedRC de la siguiente manera:

declare module 'seyfert' {
interface
interface ExtendedRC
ExtendedRC
{
ExtendedRC.developers: string[]
developers
: string[];
// más propiedades aquí...
}
}

Ubicaciones

Al igual que es posible extender la configuración base de Seyfert, también puedes ampliar el objeto de las ubicaciones de tus carpetas (locations) utilizando ExtendedRCLocations. Esto se realiza de la siguiente manera:

declare module 'seyfert' {
interface
interface ExtendedRCLocations
ExtendedRCLocations
{
ExtendedRCLocations.models: string
models
: string;
// más propiedades aquí...
}
}