CodingTrain / Discord-Bot-Examples

Bot Examples for Fall 2023
20 stars 7 forks source link

A TypeScript version would be great, it's very hard to upgrade as-is #23

Open hippietrail opened 11 months ago

hippietrail commented 11 months ago

The new JS version of this came out just when I was looking to learn to make a Discord bot. It worked great after previous false starts in other languages.

But after getting to a certain point I tried to convert it to TypeScript and found it far beyond my capabilities. Especially the deploy-command.js

dipamsen commented 11 months ago

Here's deploy-command.js converted to typescript:

// Slash Commands Deployment Script
// https://discordjs.guide/creating-your-bot/command-deployment.html#guild-commands/

// Importing modules using ES6 syntax
import { REST, RESTPutAPIApplicationGuildCommandsJSONBody, Routes } from "discord.js";
import { config } from "dotenv";
import fs from "node:fs";

config(); // Using dotenv config function directly

if (!process.env.TOKEN || !process.env.CLIENTID || !process.env.SERVERID) {
  throw new Error("Missing one or more required environment variables: TOKEN, CLIENTID, SERVERID");
}

type Command = RESTPutAPIApplicationGuildCommandsJSONBody[number];

const commands: Command[] = [];
const commandFiles = fs.readdirSync("./commands").filter((file) => file.endsWith(".ts"));

// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
for (const file of commandFiles) {
  const command = await import(`./commands/${file}`); // Using dynamic import
  if ("data" in command && "execute" in command) {
    commands.push(command.data.toJSON());
  } else {
    console.log(`[WARNING] The command ${file} is missing a required "data" or "execute" property.`);
  }
}

// Construct and prepare an instance of the REST module
const rest = new REST().setToken(process.env.TOKEN);

// and deploy your commands!
try {
  console.log(`Started refreshing ${commands.length} application (/) commands.`);

  // The put method is used to fully refresh all commands in the guild with the current set
  const data = await rest.put(Routes.applicationGuildCommands(process.env.CLIENTID, process.env.SERVERID), {
    body: commands,
  });

  if (Array.isArray(data)) {
    console.log(`Successfully reloaded ${data.length} application (/) commands.`);
  }
} catch (error) {
  // And of course, make sure you catch and log any errors!
  console.error(error);
}
hippietrail commented 11 months ago

Thanks! Finally got around to trying this. It's working with Bun but will it work with Node? I don't have my project set up properly for tsc or npx as I haven't really learned that stuff yet and I was surprised to find Coding Train hasn't done any TypeScript videos at all or I'd follow one.

For instance, these:

const commandFiles = fs.readdirSync("./commands").filter((file) => file.endsWith(".ts"));
  const command = await import(`./commands/${file}`); // Using dynamic import

Can we import .ts files directly with Node?

dipamsen commented 11 months ago

@hippietrail To run typescript in node, usually it is useful to use a package to do so, eg. tsx (https://www.npmjs.com/package/tsx), which can run* typescript files in node.

To convert a node project in javascript to typescript with tsx:

  1. Install tsx and typescript packages (npm install -D tsx typescript)
  2. Convert js code to ts. (Can import ts files normally.)
  3. Run your code with npx tsx bot.ts (instead of node bot.js)

(Here, npx is "Node Package Execute", which can run node packages as command line tools. Here, npx will run the package tsx, which runs typescript code with node.)

You can check out my branch where i have converted the code to typescript to run with tsx.


*Behind the scenes, tsx will compile the typescript code to js code, and run it normally with node, but this step is hidden from the user. There are other ts runtimes as well which run node, like ts-node.

Alternatively, a node project can be setup by using tsc - the typescript compiler, to compile source ts files into js files, and then the output js files are run with node. In this case, you'd write the ts files (with imports to other ts files), and all the ts code would be compiled to js by the compiler. node would then be pointed to the output files to run them. This is possible, but usually people just use a package like tsx which does all this behind the scenes.