【2023年1月】TypeScriptとdiscord.jsで簡単なBotを作るまで

# はじめに
今回はTypeScriptを用いて、現在時刻をチャットに表示するDiscordのボットを作成しました。
古い書き方ではうまくいかない部分がありましたので、それについても説明します。
TypeScriptとかJavaScriptがわからない方でもBotが作成できる記事になっております。

# 行う手順
1. 必要なパッケージをインスト―ル (Visual Studio Codeを用いました)
2. 下準備 (TypeScriptを使ってボットを作る準備をします)
3. コーティング
4. Botを作成してサーバーに招待
5. 実際に動かす

## 手順1 : 必要なパッケージをインストールする
さて、まずは開発に必要なパッケージをNode.jsからインストールしていきましょう。
今回用いるパッケージは以下の通りです
- TypeScript
- ts-node
- eslint
- discord.js
- dotenv

**ts-node**とは、TypeScriptをJavaScriptに変換せずそのまま実行するためのモジュールです。**eslint**はJavaScriptをきれいに書いたり、バグを発見してくれる便利なツールです。のちの設定でTypeScriptでも動作します。**discord.js**は、discordのボットをJavaScriptで作るためのもの。**dotenv**はアドミン専用のデータを保持したりするツール(らしい)です。

以下のコマンドをターミナルに入力して、インストールを行います。
```rust
//package.jsonを簡単に作成できます。-yをつけることで質問を回避できます。
> npm init -y 
//TypeScript、ts-node、eslintをローカルインストールします。
> npm install --save-dev typescript ts-node eslint
//discord.js、dotenvのインストール
> npm install discord.js dotenv
```
## 手順2 : 下準備
次に、Visual Studio Codeを使ってTypeScriptでボットを作る準備を行います。
ターミナルに以下のコマンドを入力します。
```rust
> npx tsc --init
```
すると、ディレクトリ上に``tsconfig.json``というjsonファイルが作成されます。コメントアウトの部分から、「OUTDIR」と書かれている部分を探し、以下のように書き換えます。
```rust:tsconfig.json
{
//コメント部分
"outdir": "./build"
//コメント部分
}
```
これにより、JavaScriptコードを出力するディレクトリを``build``フォルダに指定できました。
続いて、ESLintのセットアップを行います。以下のコマンドをターミナルに入力してください。
```rust
> npx eslint --init
```
入力して実行すると、セットアップウィザードが始まるので、自分の環境に合致するセットアップを行ってください。

``package.json``の設定を行います。``package.json``の``"scripts"``の中身を以下のように変更します。
```rust:package.json
"scripts":{
    "test": "ts-node src/main.ts",
	"start": "node build/main.js",
	"compile": "tsc -p ."
}
```
これにより、ターミナルでnpmコマンドが使用できるようになります(``npm run <script-name>``のように用います)。

最後に、現在のディレクトリ直下に``src``フォルダ、``build``フォルダ、``.env``ファイルを作成します。
**``src``フォルダ**は本体となるTypeScriptファイルを保持する場所、**``build``フォルダ**はJavaScriptコードを出力する場所、**``.env``ファイル**はトークン番号やAPI鍵など、機密情報を保持する場所として機能します。

また、Gitを使って作業している場合、``.gitignore``ファイルや``README``を作成しておくと便利です。
ここまでで、ディレクトリの中身は以下のようになります。これで下準備が完了です。
![スクリーンショット 2023-01-09 223836.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2665102/88fd9fcd-c501-7834-b9f4-d32797a8c66c.png)

## 手順3 : コーディング
それでは、実際のコーディングを行います。今回は時刻を表示するだけの簡単なBotですので、スクリプト1枚でコーディングを完結させてしまいます。``src``フォルダに``main.ts``ファイルを作成してください。中身を以下のようにします。

```typescript:src/main.ts
//必要なパッケージをインポートする
import { GatewayIntentBits, Client, Partials, Message } from 'discord.js'
import dotenv from 'dotenv'

//.envファイルを読み込む
dotenv.config()

//Botで使うGatewayIntents、partials
const client = new Client({
  intents: [
    GatewayIntentBits.DirectMessages,
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMembers,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
  partials: [Partials.Message, Partials.Channel],
})

//Botがきちんと起動したか確認
client.once('ready', () => {
    console.log('Ready!')
    if(client.user){
        console.log(client.user.tag)
    }
})

//!timeと入力すると現在時刻を返信するように
client.on('messageCreate', async (message: Message) => {
    if (message.author.bot) return
    if (message.content === '!time') {
        const date1 = new Date();
        message.channel.send(date1.toLocaleString());
    }
})

//ボット作成時のトークンでDiscordと接続
client.login(process.env.TOKEN)
```
### 2022年以前と変化している部分
新しいdiscord.jsで変化しているのは、Botで使うGetwayIntents、partialsを定義する部分です。はじめ開発している時、少し古い資料を参考にしていたので、``Client``オブジェクトを以下のように記述していました。
```typescript
const client = new Client({
    intents: ['DirectMessages','Guilds', 'GuildMembers', 'GuildMessages','MessageContent'],
})
```
私と友人の環境で実行させたところ、たまに動いたり動かなくなったり、といった挙動を示しました。調べていくうちに、どうやら**v13とv14で、intentsの記述方法が異なる**ことに行きつきました。
新しく``GatewayIntentBits``というモジュールが誕生しており、このクラスの中に各intentsが含まれているという仕様に変わっていたようです。また、``partials``モジュールによって、データの一部のみで特定のイベントを実行できるようになります(詳しくは公式を参照してください)。

## 手順4 : Botを作成してサーバーに招待
[Discord Developer Portal](https://discord.com/developers/applications)にアクセスして、New Application→Add Botで、Botが簡単に作成できます。名前はお好みで。
右側の「Bot」メニューをクリックすると、「Reset Token」というボタンがあると思います。それをクリックしてトークンを発行してください。
![スクリーンショット 2023-01-10 101331.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2665102/16e48fe6-72d9-c732-6966-9c62a9fd4106.png)
そしたら、発行したトークンを``.env``ファイルに貼り付けます。``.env``ファイルを以下の画像のように更新してください。クオーテーションの中身はトークン番号です。
![スクリーンショット 2023-01-10 101455.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2665102/5d4f2b95-7760-9038-31fe-e51353fc2bc1.png)
続いて、「Bot」メニューにある「Privileged Gateway Intents」欄に行き、全てを有効にします。
![スクリーンショット 2023-01-10 104732.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2665102/f90d582d-8a25-86e0-c54c-fb44ac914af6.png)
最後に、「OAuth2」メニューをクリックしたら表示される「URL Generator」メニューに行くと、「Scopes」欄があります。これの「Bot」にチェックを入れます。![スクリーンショット 2023-01-10 102310.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2665102/051609f3-328d-ca08-fcf7-420a9629091d.png)
そしたら、下に「Bot Permissions」という欄が生まれるので、「Administrator」にチェックを入れます。本当はこれにチェックを入れるのは権限的に良くないみたいですが、今回はとりあえず動かすだけなので。
![スクリーンショット 2023-01-10 102522.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2665102/8dc439f3-2d83-91a7-ddab-6b6e3c8a17ec.png)
チェックを入れると、すぐ下にリンクが生成されます。このリンクを開くと、Botをサーバーに招待することができます。これでBotの生成＆招待は完了です。

## 手順5 : 実際に動かす
それでは、実際にBotを起動します。ターミナルに
```rust
> npm run start
```
と入力します。これでサーバーのBotが起動したのが確認できると思います(オンライン表示になっている)。プライベートでないテキストチャンネルに``!time``と入力すると...
![スクリーンショット 2023-01-10 104606.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2665102/c238d891-0a06-b81b-06d0-e851d07463bb.png)
無事に現在時刻が返ってきてくれました。今回は以上です。