【问题标题】:Node.js and Typescript, how to dynamically access imported modulesNode.js 和 Typescript,如何动态访问导入的模块
【发布时间】:2020-07-21 15:39:06
【问题描述】:

我正在努力在 TypeScript 中创建一个不和谐的机器人。我想创建一个通用的命令调度程序,这是我到目前为止的工作:

app.ts:

import * as Discord from 'discord.js';
import * as config from '../config'
import * as commands from './Commands/index'

const token : string = config.Token;

const _client = new Discord.Client();

_client.on('message', (msg) => {
    let args : Array<string> = msg.content.split(' ')
    let command : string = args.shift() || " ";

    if(!command.startsWith("!")) return;
    else{
        commands[`${command.toLower().substring(1)}`]
    }

})

命令/索引.ts

export {default as ping} from './ping';
export {default as prong} from './prong';

Ping.ts:所有命令的结构相同

import { Message } from "discord.js";

export default {
    name : 'ping',
    description: 'Ping!',
    execute(message: Message, args: Array<string>){
        message.channel.send('Pong.');
    }
}

在索引命令导入时,我可以使用以下命令成功调用正确的执行函数:

commands['pong'].execute()

但是,当尝试像这样动态索引它时:

commands[command].execute()

我收到以下错误:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'typeof import("c:/Users/alexs/Desktop/Discord Bot/src/Commands/index")'. No index signature with a parameter of type 'string' was found on type 'typeof import("c:/Users/alexs/Desktop/Discord Bot/src/Commands/index")'

无论如何我可以将命令导入类型转换为某种对象或集合吗?如果没有,有没有办法我可以创建某种访问器来完成这项工作?我是打字稿的新手,很好奇有什么可能。

【问题讨论】:

  • 你怎么打电话给commands[command].execute()command 变量从何而来?

标签: javascript node.js typescript discord.js


【解决方案1】:

我为您的命令建议一种不同的方法,这种方法可以解决两件事:

  • 别忘了正确导出文件
  • 您会收到类型安全的命令

让我们首先为你的命令创建一个接口,这个接口描述元数据,你想添加多少就添加多少

export interface Command {
  name: string
  description: string
  // Making `args` optional
  execute(message: Message, args?: string[]) => any
}

现在您已经为命令设置了形状,让我们确保您的所有命令都具有正确的形状

import { Command } from "./types"

// This will complain if you don't provide the right types for each property
const command: Command = {
  name: "ping",
  description: "Ping!",
  execute(message: Message, args: string[]) => {
    message.channel.send("Pong")
  }
}

export = command

下一部分是加载你的命令,discord.js 有 glob 作为依赖项,它可以帮助你轻松读取目录中的文件,让我们使用一些实用程序,这样我们就可以很好地使用 async / await

import glob from "glob" // included by discord.js
import { promisify } from "util" // Included by default
import { Command } from "./types"

// Make `glob` return a promise
const globPromise = promisify(glob)

const commands: Command = []

client.once("ready", async () => {
  // Load all JavaScript / TypeScript files so it works properly after compiling
  // Replace `test` with "await globPromise(`${__dirname}/commands/*.{.js,.ts}`)"
  // I just did this to fix SO's syntax highlighting!
  const commandFiles = test

  for (const file of commandFiles) {
    // I am not sure if this works, you could go for require(file) as well
    const command = await import(file) as Command
    commands.push(command)
  }
})

const prefix = "!"

client.on("message", message => {
  // Prevent the bot from replying to itself or other bots
  if (message.author.bot) {
    return
  }

  const [commandName, ...args] = message.content
    .slice(prefix.length)
    .split(/ +/)

  const command = commands.find(c => c.name === commandName)

  if (command) {
    command.execute(message, args)
  }
})

我希望这能给你一个好的起点,并向你展示 TypeScript 的力量

【讨论】:

    【解决方案2】:

    你可以导入类型,然后像这样进行转换

    commands[command as Type].execute();
    

    【讨论】:

      猜你喜欢
      • 2019-12-04
      • 2017-08-20
      • 2013-08-09
      • 2011-11-09
      • 2019-02-27
      • 2021-08-21
      • 2015-09-19
      • 2013-04-12
      • 2017-07-13
      相关资源
      最近更新 更多