Skip to content

Understanding 'declare module'

The following code snippets can be used in any TypeScript file in your project. However, it’s recommended to place a single declare module 'seyfert' in the main file src/index.ts that contains everything your bot needs.

Clients

Seyfert provides several client types to instantiate your bot, which could cause confusion when referencing the client in different parts of your code. To avoid this, you can specify the client type you’re using to TypeScript. Be sure to choose only one of the following three implementations:

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

Middlewares

To use your middlewares throughout the project, you need to inform TypeScript about their structure and composition. Export all middlewares from your code and provide them to Seyfert as follows:

// Assuming you exported all middlewares from './middlewares';
import type * as allMiddlewares from './middlewares';
declare module 'seyfert' {
interface RegisteredMiddlewares extends ParseMiddlewares<typeof allMiddlewares> {}
}

This applies similarly to global middlewares, which are automatically executed on every command, even if they aren’t explicitly specified in it.

// Assuming you exported all global middlewares from './globalMiddlewares';
import type * as globalMiddlewares from './globalMiddlewares';
declare module 'seyfert' {
interface GlobalMetadata extends ParseMiddlewares<typeof globalMiddlewares> {}
}

If you’re not yet familiar with middlewares, you can review their use cases and structure in their dedicated section.

Languages

To correctly configure types for languages, it’s recommended to establish a primary or base language that you always update. This way, all types will derive from this language, making it easier to keep the rest of the translations up to date.

// Assuming your base language is located in './langs/en';
import type * as defaultLang from './langs/en';
declare module 'seyfert' {
interface DefaultLocale extends ParseLocales<typeof defaultLang> {}
}

If you didn’t know that Seyfert has an automatic language system, we recommend visiting the dedicated section on this.

Contexts

We often need to extend contexts to add useful properties or methods, which also requires updating the types.

If you’ve used extendContext for this, you can use the following code to infer the type returned by your function and add it to the context:

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]) => {
otter: string;
}
context
=
extendContext<{
otter: string;
}>(cb: (interaction: Parameters<NonNullable<BaseClientOptions["context"]>>[0]) => {
otter: string;
}): (interaction: Parameters<NonNullable<BaseClientOptions["context"]>>[0]) => {
otter: 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
) => ({
otter: string
otter
: 'cute' }));
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]) => {
otter: string;
}
context
> {}
}

If you’re not yet familiar with how Seyfert allows you to easily modify and extend the context, you can review its dedicated section.

Command Properties

We often need to categorize some commands or simply assign an identifier for something.

To achieve this, we can use 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 'onlyForAdmins' is missing in type '{ category: string; }' but required in type 'ExtraProps'.
ExtraProps.category?: string
category
: '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
: 'test command',
props: {}
Error ts(2741) ― Property 'onlyForAdmins' 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.onlyForAdmins: boolean
onlyForAdmins
: boolean;
ExtraProps.disabled?: true
disabled
?: true;
ExtraProps.category?: string
category
?: string
}
}

Internal Options

Since Seyfert supports various modes of operation, it’s necessary to add types as required by your implementations. For this, InternalOptions exists as an interface designed to include properties that transform Seyfert types into something more comprehensive.

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

withPrefix

Setting this property to true tells Seyfert that the context can include either a message or an interaction, both of which will be optional. By default, .interaction is always present in the context.

asyncCache

Setting this property to true tells Seyfert whether the cache will return a promise. By default, Seyfert uses MemoryAdapter, a RAM cache that doesn’t return promises, while RedisAdapter does.

Configuration

In Seyfert, you can add more properties to the configuration file seyfert.config.mjs, regardless of whether you’re using the http or bot configuration. This can be done using ExtendedRC as follows:

declare module 'seyfert' {
interface
interface ExtendedRC
ExtendedRC
{
ExtendedRC.developers: string[]
developers
: string[];
// more properties here...
}
}

Locations

Just as you can extend Seyfert’s base configuration, you can also extend the folder locations object using ExtendedRCLocations. This can be done as follows:

declare module 'seyfert' {
interface
interface ExtendedRCLocations
ExtendedRCLocations
{
ExtendedRCLocations.models: string
models
: string;
// more properties here...
}
}