Discord.js Guide : Property 'commands' does not exist on type 'Client<boolean>' in Typescript
Asked Answered
R

4

7

node:v16.11.0 "discord.js": "^13.2.0"

I am setting up an example Discord.js bot.

In this guide, I am to the point of adding this line:

client.commands = new Collection();

Typescript then complains with: Property 'commands' does not exist on type 'Client<boolean>'

This answer seems to be in the same vein as what I want. However I'm still running into some problems. If I add a declare module "discord.js" and declare new typings, it doesn't seem to extend the existing type, it overwrites it. And when when I do, it doesn't know what a Collection is in my custom typings file, since that's custom to the new Discord.js library. I can't help but feel this shouldn't be required in an official guide.

I'm wondering if anyone else has made a typescript Discord bot and found a newer solution to this problem.

Thank you for your time.

Redhanded answered 8/10, 2021 at 18:54 Comment(1)
I've yet to try this but: Try creating a new class that extends discord.js's Client and add whatever entries you need. Typings should be carried onto the new classTimbered
R
16

-Edit-

So I had the opportunity of finding my own question in a search and seeing I'd originally answered the question wrong. It turns out that the reason we are getting this error when following the Discord.js guide is because there is no commands property on the Client class at all. It's just a pattern that the guide uses and Typescript calls it out.

Once I had Typescript set up correctly for my project, adding that commands was going to represent a Collection<any, any> worked fine.

src/@types/discord.d.ts

import { Collection } from "discord.js";

declare module "discord.js" {
  export interface Client {
    commands: Collection<any, any>;
  }
}

tsconfig.json

{
  "compilerOptions": {
    "typeRoots": ["src/@types", "node_modules/@types"],
    "outDir": "dist"
  },
  "include": ["src"],
  "exclude": ["node_modules"],
  "extends": "@tsconfig/node18/tsconfig.json"
}

-Old Answer-

Okay. So I figured it out.

Create types/common/discord.d.ts

And don't do what I did and just include this:

declare module "discord.js" {
  export interface Client {
    commands: Collection<unknown, any>
  }
}

Make sure this is at the top.

import { Collection } from "discord.js";

Then it will actually extend the existing one and bring in Collection for the definition instead of replacing it.

This solution also required "@typescript-eslint/no-explicit-any": "off" to be added to es-lint, thanks to Collection extending Map and taking any value.

Redhanded answered 12/10, 2021 at 1:14 Comment(1)
Didn't work for me. The import { Collection } line now throws the following errors Circular definition of import alias 'Collection'.ts(2303) and Module '"discord.js"' declares 'Collection' locally, but it is not exported.ts(2459)Colin
C
1

You have two options go: the hard way or the easy way. The hard way is this:

declare module "discord.js" {
  export interface Client {
    commands: Collection<unknown, any>
  }
}

And the easy way is to extend the discord class which is what everyone does:

// utils/Client.ts
import { Client, Collection } from "discord.js"

export default class MyClient extends Client {
  collection: Collection<any, any> // use correct type :)
  constructor(options) {
   super(options)
   this.collection = new Collection();
   this.loadCommands()
  }
  loadCommands() {
   // enter code here
  }
}
Chu answered 7/1, 2023 at 14:45 Comment(1)
Doesn't work for me, still shows the error: Property 'commands' does not exist on type 'Client<true>', but in IDE that error doesn't show.Sushi
M
0

I know it's already answered but for those who don't want to import stuff just do this:

module "discord.js" {
    export interface Client {
        foo: number;
    }
}

export {}
Mass answered 8/3, 2022 at 16:1 Comment(1)
Do this where? please share more info about your solution.Niello
F
0

As mentioned in their documentation. it is recommended to extend the base Client and typecast it to add the commands property. You can achieve this by creating a new interface as follows:

interface ClientWithCommands extends Client {
  commands: Collection<string, any>
}

Once you have defined the interface, you can proceed with typecasting the Client instance using the "as" keyword:

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
  ],
}) as ClientWithCommands

Now, you can proceed to add the commands as follows:

client.commands = new Collection()
...
Ferrigno answered 23/7, 2023 at 10:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.