Creating your first Discord bot using TypeScript
Fellipe Utaka
Posted on March 19, 2023
Discord is a popular platform for communication among gamers and communities. One of the key features of Discord is its ability to host bots, which can automate tasks and provide helpful services for users. In this tutorial, we'll go through the steps of creating your first Discord bot using TypeScript.
Prerequisites
Before we begin, you'll need to have the following:
Node.js installed on your computer.
Setting up a new bot
To create a new bot, you'll need to follow these steps:
1. Go to the Discord Developer Portal and create a new application.
2. Give your application a name and click "Create".
3. Copy your Application ID selecting and copying or just click on "Copy" button.
4. On the left-hand side, click on "Bot" and then click "Add Bot".
5. Customize your bot's name and profile picture as desired, and then click "Save Changes".
6. Under the "Token" section, click "Copy" to copy the bot's token to your clipboard. This token will be used later to authenticate your bot.
Setting up the project
Now that we have our bot's token and Application Client ID, let's set up our TypeScript project. Follow these steps:
1. Create a new directory for your project and navigate into it.
2. Run npm init
to initialize your project with a package.json
file.
3. Install the following packages:
npm install discord.js dotenv
4. Install the following dev dependencies:
npm install -D typescript tsx tsup
5. Add some scripts to your package.json
:
{
"dev": "tsx watch src/index.ts",
"start": "node dist/index.js",
"build": "tsup src/index.ts --minify"
}
6. Create a tsconfig.json
file to configure TypeScript:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"rootDir": "./src",
"outDir": "./dist",
"removeComments": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"strictNullChecks": true,
"skipLibCheck": true
}
}
Setting up environment variables
To keep sensitive information like our bot's token secure, we'll use environment variables. Follow these steps to set them up:
Create a .env
file in the root of your project directory.
Add the following line to the file, replacing DISCORD_TOKEN with the bot token you copied earlier and DISCORD_CLIENT_ID with the bot client id:
DISCORD_TOKEN=<DISCORD_TOKEN>
DISCORD_CLIENT_ID=<DISCORD_CLIENT_ID>
Now, create a src
folder and a config.ts
file to get them.
import dotenv from "dotenv";
dotenv.config();
const { DISCORD_TOKEN, DISCORD_CLIENT_ID } = process.env;
if (!DISCORD_TOKEN || !DISCORD_CLIENT_ID) {
throw new Error("Missing environment variables");
}
export const config = {
DISCORD_TOKEN,
DISCORD_CLIENT_ID,
};
Creating your first command
In this tutorial, I'm going to create a command called ping that will return "Pong!". To do that, you just have to export a SlashCommand data containing all information about your command and a function to handle it. Create a commands
folder inside the src
folder and create a ping.ts
file inside it.
import { CommandInteraction, SlashCommandBuilder } from "discord.js";
export const data = new SlashCommandBuilder()
.setName("ping")
.setDescription("Replies with Pong!");
export async function execute(interaction: CommandInteraction) {
return interaction.reply("Pong!");
}
You can create a index.ts
file inside the commands
folder to export all commands in one file.
import * as ping from "./ping";
export const commands = {
ping,
};
Great! You did it! But there is a problem. How the servers which the bot is added know the commands it has? To solve this problem, we need to register all the commands to each server.
Deploying your command
To deploy your commands, we will create a deploy-commands.ts
file to register the commands in the corresponding server. Let's do it:
import { REST, Routes } from "discord.js";
import { config } from "./config";
import { commands } from "./commands";
const commandsData = Object.values(commands).map((command) => command.data);
const rest = new REST({ version: "10" }).setToken(config.DISCORD_TOKEN);
type DeployCommandsProps = {
guildId: string;
};
export async function deployCommands({ guildId }: DeployCommandsProps) {
try {
console.log("Started refreshing application (/) commands.");
await rest.put(
Routes.applicationGuildCommands(config.DISCORD_CLIENT_ID, guildId),
{
body: commandsData,
}
);
console.log("Successfully reloaded application (/) commands.");
} catch (error) {
console.error(error);
}
}
Initializing your bot
To initialize your bot, you can create a bot.ts
or index.ts
file inside src
folder. In this tutorial, I will create a index.ts
instead.
For the bot works properly, you need to follow these steps:
1. Create a new Discord Client and set its intents to determine which events the bot will receive information about. In this example, the bot will receive information about guilds, guild messages, and direct messages:
import { Client } from "discord.js";
const client = new Client({
intents: ["Guilds", "GuildMessages", "DirectMessages"],
});
2. Add a console.log when the bot is ready:
client.once("ready", () => {
console.log("Discord bot is ready! 🤖");
});
3. Deploy commands when new guild has been created:
client.on("guildCreate", async (guild) => {
await deployCommands({ guildId: guild.id });
});
4. Run corresponding command when new user interaction has been created:
client.on("interactionCreate", async (interaction) => {
if (!interaction.isCommand()) {
return;
}
const { commandName } = interaction;
if (commands[commandName as keyof typeof commands]) {
commands[commandName as keyof typeof commands].execute(interaction);
}
});
5. Log in the client using your token:
client.login(config.DISCORD_TOKEN);
After all steps, your file should look like that:
import { Client } from "discord.js";
import { config } from "./config";
import { commands } from "./commands";
import { deployCommands } from "./deploy-commands";
const client = new Client({
intents: ["Guilds", "GuildMessages", "DirectMessages"],
});
client.once("ready", () => {
console.log("Discord bot is ready! 🤖");
});
client.on("guildCreate", async (guild) => {
await deployCommands({ guildId: guild.id });
});
client.on("interactionCreate", async (interaction) => {
if (!interaction.isCommand()) {
return;
}
const { commandName } = interaction;
if (commands[commandName as keyof typeof commands]) {
commands[commandName as keyof typeof commands].execute(interaction);
}
});
client.login(config.DISCORD_TOKEN);
Very good! Now you just have to run npm run dev
and add your bot to some server and use /ping in some text channel.
If you just want to clone the repository, follow the link below to the repository on GitHub. I would be very happy if you leave a star.
Posted on March 19, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.