【问题标题】:Extending a class of a node_module (Discord.Js <Client>). Error: Cannot find module './@types'扩展一个 node_module 的类(Discord.Js <Client>)。错误:找不到模块“./@types”
【发布时间】:2021-07-26 21:24:46
【问题描述】:

我是 TypeScript 的新手,我想在创建一个非常简单的 Discord Bot 的同时学习该语言,使用一个名为 Discord.JS 的模块。 我的问题是我想扩展他们的Client 类并添加我自己的方法和对象,以便在名为 myClient

的类中将内容存储在内存中

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

├── package.json
├── package-lock.json
├── src
│   ├── bot.ts
│   ├── commands
│   │   └── test.ts
│   └── @types
│       └── index.d.ts
└── tsconfig.json

@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;
  }
}

bot.ts

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 时,我收到以下错误:

但是,如果我将 export class myClient extends Client { ... } 代码 sn-p 从 index.d.ts 移动到 bot.ts,它就可以工作。这让我很困惑,因为我不想在那里上课。

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

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

【问题讨论】:

  • 只是为了填写,我尝试在我的自定义对象中进行转换,如 (client as any).myObject 以避免上述麻烦,但这并没有给我任何类型和自动完成,所以我想不要这样做。
  • 您确定 discord.js 与 typescript 兼容吗?
  • .d.ts 文件不应该包含逻辑,只有类型。在.ts 文件中扩展类,并将基类型放在.d.ts 文件中。 typescriptlang.org/docs/handbook/declaration-files/…
  • @AnžePintar 是的。
  • @Lioness100 哦,这就解释了,谢谢。是的,将其移至 .ts 文件是可行的,我将按照链接确保我做对了。

标签: typescript discord.js


【解决方案1】:

我不知道我的做法是否是最好的,但这就是我解决问题的方法。 Lioness100 在 cmets 中也提到过。

创建了一个 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));
    });
  }
}

bot.ts 中使用import myClient from './client' 将其导入,现在我可以使用其属性和方法访问 myClient。在其中存储命令及其冷却时间并不是最佳做法,但我正在尝试使用 TS。

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

【讨论】:

  • .d.ts 文件通常只与declare module '...' 配对使用。如果您不尝试为 npm 模块增加/创建类型,而是尝试导出仅与您的项目相关的接口、类型和类,它可能应该放在常规的 .ts 文件中。我个人喜欢有一个interfaces 文件夹,每个文件一个接口,例如ApplicationCommandModule.ts。有些人喜欢将每个接口放在一个.ts 文件中,有些人喜欢将其放在与之相关的文件中(而不是将其与逻辑分开)。不管你想做什么,我认为它不应该是.d.ts
  • @Lioness100 我明白了。在阅读了您的评论后,我阅读了它,我想我已经掌握了它。我检查了 GitHub 上的一些 TypeScript 项目,看看我喜欢哪种风格,但是,我决定如果我只有 1 或 2 个接口来保持逻辑,例如。 WS 交互接口,因为它们得到了很多,所以我将它们放在一个单独的 .ts 文件中。非常感谢你的帮助^^这是我在TS的第一天,有点困惑来自JS哈哈。
猜你喜欢
  • 2019-01-18
  • 1970-01-01
  • 1970-01-01
  • 2017-05-22
  • 2020-02-22
  • 2021-11-18
  • 1970-01-01
  • 2021-01-04
  • 1970-01-01
相关资源
最近更新 更多