Typescript 扩展节点模块的类(Discord.Js<;Client>;)。错误:找不到模块'/@类型';

Typescript 扩展节点模块的类(Discord.Js<;Client>;)。错误:找不到模块'/@类型';,typescript,discord.js,Typescript,Discord.js,我对TypeScript相当陌生,我想在创建一个非常简单的Discord机器人的同时学习该语言,使用一个名为的模块。 我的问题是,我想扩展它们的类,并添加我自己的方法和对象,以便在名为myClient 我的目录树(不包括/dist) @types/index.d.ts import { Client, Message, PermissionString, TextChannel, VoiceConnection, Collection, ClientOptions } from "di

我对TypeScript相当陌生,我想在创建一个非常简单的Discord机器人的同时学习该语言,使用一个名为的模块。 我的问题是,我想扩展它们的类,并添加我自己的方法和对象,以便在名为myClient

我的目录树(不包括/dist)

@types/index.d.ts

import { Client, Message, PermissionString, TextChannel, VoiceConnection, Collection, ClientOptions } from "discord.js";

export type ApplicationCommandOptionChoice = {
  readonly name: String;
  readonly value: String | number;
}

export type ApplicationCommandOption = {
  readonly type: number;
  readonly name: String;
  readonly description: String;
  readonly required?: Boolean;
  readonly choices?: Array<ApplicationCommandOptionChoice>;
  readonly options?: Array<ApplicationCommandOption>;

}

export interface ApplicationCommandModule<object> {
  readonly name: String;
  readonly description: String;
  readonly options?: Array<ApplicationCommandOption>;
  readonly default_permission?: Boolean;
  readonly permissions: PermissionString = 'SEND_MESSAGES';
  readonly usage: String;
  readonly devOnly?: Boolean;
  readonly execute: (args?: Array<T>) => any;
}

export class myClient extends Client {
  constructor(options: ClientOptions) {
    super(options);
    this.commands = new Collection();
  }
  public commands: Collection<String, object>;
  

  lookupCommand(name: String) {
    const command = this.commands.get(name);
    if (command) return command as ApplicationCommandModule<object>;
    return null;
  }

  executeCommand(name: String, ...args: any[]) {
    const command = this.commands.get(name);
    if (command) return (command as ApplicationCommandModule<object>).execute(args);
    return null;
  }
}
import Discord from 'discord.js';
import { myClient }  from './@types';

const client = new myClient({ intents: Discord.Intents.NON_PRIVILEGED });
tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "outDir": "./dist",
    "strict": true,
    "types": ["./src/@types"],
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}
当我运行npm run dev即
ts node dev--respawn./src/bot.ts
时,我得到以下错误:

但是,如果我将
导出类myClient extensed Client{…}
代码段从index.d.ts移动到bot.ts,它就会工作。这让我很困惑,因为我不想在那里上课

那么,如何正确导入
myClient
类呢?还有,为什么它是从@types自动导入的,这不应该是“已知”的吗


更新:我将我的
myClient
类移动到一个名为client.ts的.ts文件中,并导入该类,它就可以工作了。为什么会有这种行为?类只能在.ts文件中吗?当我检查node_模块时,它们的类扩展在index.d.ts中,而不是它们的方法中。因此,如果我把我的类结构放在index.d.ts中,我应该把它的方法放在哪里?

我不知道我这样做是否是最好的,但下面是我解决问题的方法。狮子座100在评论中也提到了这一点

创建了一个client.ts文件,并将我的类放在其中

import { Client, ClientOptions, Collection } from "discord.js";
import { ApplicationCommandModule } from "./@types";

export default class myClient extends Client {
  public commands: Collection<String, ApplicationCommandModule>;
  public cooldowns: Collection<String, Collection<String, number>>;

  constructor(options: ClientOptions) {
    super(options);
    this.commands = new Collection();
    this.cooldowns = new Collection();
    this.loadCommads();
  }
  
  private loadCommads():void {
    const commandFiles = fs.readdirSync(`${__dirname}/commands`).filter((file) => file.endsWith('.js') || file.endsWith('.ts'));
    commandFiles.forEach((file) => {
      const command = require(`${__dirname}/commands/${file}`);
      this.commands.set(command.default.name, (command.default as ApplicationCommandModule));
    });
  }
}
从“discord.js”导入{Client,ClientOptions,Collection};
从“/@types”导入{ApplicationCommandModule};
导出默认类myClient扩展客户端{
公共命令:集合;
公共冷却:收集;
构造函数(选项:ClientOptions){
超级(期权);
this.commands=新集合();
this.cooldowns=新集合();
这是loadCommads();
}
私有loadCommads():void{
const commandFiles=fs.readdirSync(`${uu dirname}/commands`).filter((file)=>file.endsWith('.js')| | file.endsWith('.ts'));
commandFiles.forEach((文件)=>{
const command=require(`${uu dirname}/commands/${file}`);
this.commands.set(command.default.name,(command.default作为ApplicationCommandModule));
});
}
}
使用
import myClient from./client'
bot.ts中导入了它,现在我可以使用它的属性和方法访问myClient。在那里存储命令及其冷却时间并不是最好的做法,但我正在试验TS


如果此实现有问题,请进行编辑或评论。

只是为了填写,我尝试在自定义对象中强制转换,如(客户机).myObject以避免上述麻烦,但这不会给我任何类型和自动完成,因此我不想这样做。您确定discord.js与typescript兼容吗?
.d.ts
文件不应该包含逻辑,只包含类型。在
.ts
文件中扩展类,并将基本类型放入
.d.ts
文件中@安žePintar是的。@Lioness100哦,这就解释了,谢谢。是的,将其移动到.ts文件工作正常,我将按照链接确保操作正确。
.d.ts
文件通常仅与
声明模块“…”成对使用。
。如果您不尝试为npm模块扩充/创建类型,而是尝试导出仅与您的项目相关的接口、类型和类,那么它可能应该放在常规的
.ts
文件中。我个人喜欢有一个
interfaces
文件夹,每个文件有一个接口,比如
ApplicationCommandModule.ts
。有些人喜欢将每个接口放在一个
.ts
文件中,有些人喜欢将其放在相关的文件中(而不是将其与逻辑分离)。不管你想怎么做,我不认为应该使用
.d.ts
@Lioness100。在读了你的评论后,我读了一遍,我想我已经掌握了窍门。我检查了GitHub上的一些TypeScript项目,看看我喜欢哪种样式,但是,我决定,如果我只有1或2个接口来保持逻辑,例如WS-Interaction接口,因为它们有很多,我将它们放在一个单独的.ts文件中。非常感谢你的帮助^^这是我在TS上的第一天,JS让我有点困惑哈哈。
import { Client, ClientOptions, Collection } from "discord.js";
import { ApplicationCommandModule } from "./@types";

export default class myClient extends Client {
  public commands: Collection<String, ApplicationCommandModule>;
  public cooldowns: Collection<String, Collection<String, number>>;

  constructor(options: ClientOptions) {
    super(options);
    this.commands = new Collection();
    this.cooldowns = new Collection();
    this.loadCommads();
  }
  
  private loadCommads():void {
    const commandFiles = fs.readdirSync(`${__dirname}/commands`).filter((file) => file.endsWith('.js') || file.endsWith('.ts'));
    commandFiles.forEach((file) => {
      const command = require(`${__dirname}/commands/${file}`);
      this.commands.set(command.default.name, (command.default as ApplicationCommandModule));
    });
  }
}