spearkit
Guides

Events

event() defines a reusable, loadable discord.js event listener with a fully-typed handler. The handler's arguments are inferred from discord.js' ClientEvents, so you never…

import { event } from "spearkit";

export default event("messageCreate", (message) => {
  if (message.author.bot) return;
  // message is fully typed as Message
});

Defining an event

event has two forms. The positional form takes the event name and handler:

import { event } from "spearkit";

const onMessage = event("messageCreate", (message) => {
  // message: Message
  console.log(message.content);
});

const onReady = event("clientReady", (client) => {
  // client: Client<true> — the ready client
  console.log(`Logged in as ${client.user.tag}`);
});

The object form (EventConfig) additionally accepts once, which runs the handler at most once and then auto-detaches:

import { event } from "spearkit";

const onceReady = event({
  name: "clientReady",
  once: true,
  run: (client) => {
    // client: Client<true>
    console.log(`Ready as ${client.user.tag}`);
  },
});

Both forms return an EventDef — a type-erased, ready-to-attach listener ({ name, once, attach, detach }). Register it like anything else:

import { SpearClient } from "spearkit";

const client = new SpearClient();
client.register(onMessage, onReady);

Handlers are fully typed from ClientEvents

The event name drives the parameter types. There is nothing to import or annotate — picking "messageCreate" types the argument as Message, picking "guildMemberAdd" types it as GuildMember, and so on. The handler type is exported as EventHandler<E> ((...args: ClientEvents[E]) => Awaitable<void>).

import { event } from "spearkit";

const onJoin = event("guildMemberAdd", (member) => {
  // member: GuildMember
  void member.roles.add("123456789012345678");
});

const onReaction = event("messageReactionAdd", (reaction, user) => {
  // reaction: MessageReaction | PartialMessageReaction
  // user: User | PartialUser
  console.log(`${user.id} reacted with ${reaction.emoji.name}`);
});

Intents are required

An event only fires if the client connected with the matching gateway intents. For example, messageCreate with message content needs Intents.messages (or at least the GuildMessages / MessageContent bits); guildMemberAdd needs GuildMembers. See Client for the intent presets.

Errors are routed, not fatal

If a handler throws synchronously or rejects a returned promise, spearkit catches it and emits it on the client's error event instead of crashing the process. Listen for error to log or report failures centrally:

import { SpearClient } from "spearkit";

const client = new SpearClient();

client.on("error", (err) => {
  console.error("A handler failed:", err);
});

Inline listeners still work

Because spearkit re-exports discord.js, the plain client.on(...) / client.once(...) listeners work exactly as before — they are the same methods. Reach for them for quick, inline, client-local listeners:

import { SpearClient } from "spearkit";

const client = new SpearClient();
client.on("guildCreate", (guild) => console.log(`Joined ${guild.name}`));

Use event() when you want a listener that is reusable and loadable — a self-contained module you can export, register from anywhere, or pick up via client.load(...). Note that inline client.on listeners do not get the automatic error-routing that event() handlers do.

The EventRegistry

client.events is an EventRegistry. The client attaches it automatically at construction and again when you register an event, so you usually never call its methods directly. They are available for advanced control:

MemberTypeDescription
add(...defs)thisRegister one or more EventDefs (and attach them to already-attached clients).
sizenumberNumber of registered listeners.
attachAll(client)voidAttach every registered listener to a client.
detachAll(client)voidDetach every registered listener from a client.
import { SpearClient, event } from "spearkit";

const client = new SpearClient();
client.events.add(event("warn", (info) => console.warn(info)));

console.log(client.events.size); // 1

// Detach all spearkit-managed listeners (e.g. before a hot reload).
client.events.detachAll(client);

See also

On this page