Node.js и Typescript, как получить динамический доступ к импортированным модулям - PullRequest
0 голосов
/ 09 апреля 2020

Я работаю над созданием диска разногласий в TypeScript. Я хотел создать универсальный диспетчер команд c, и вот моя работа:

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")'

В любом случае можно ли ввести команду import как какой-то объект или коллекцию? Если нет, то есть ли способ, которым я мог бы создать своего рода акссессор для этой работы? Я новичок в машинописи и мне интересно, что это возможно.

Ответы [ 2 ]

1 голос
/ 09 апреля 2020

Я предлагаю другой подход для ваших команд, этот подход исправляет 2 вещи:

  • Вы не забыли правильно экспортировать файлы
  • Вы получаете команды безопасного типа

Давайте сначала создадим интерфейс для ваших команд, этот интерфейс описывает метаданные, добавьте столько, сколько вы хотите

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 в качестве зависимости, которая может помочь вам легко читать файлы в каталоге, давайте использовать некоторые утилиты, чтобы мы могли использовать asyn c / 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

0 голосов
/ 09 апреля 2020

Вы можете импортировать тип и затем разыграть его так:

commands[command as Type].execute();
...