Pesquisa de site

typescript - isto ao chamar funções assíncronas com decoradores


Eu tenho um arquivo chamado commands.js. No meu conceito, ele será chamado antes da função real ser chamada e fará verificações se message possui content e se content é igual (ou começa como) cmd. Tudo estava ok antes de eu tornar minha função assíncrona. Eu converti o arquivo com o decorador (seguindo dicas do tsc) e há o seguinte resultado:

import { Message } from "discord.js";

export function command(cmd:string, eq:boolean=false) {
    return (target, propertyKey: string, descriptor: TypedPropertyDescriptor<(msg: Message) => Promise<void>>) => {
        let f = descriptor.value;
        descriptor.value = (msg: Message) => {
            if(!msg.content || msg.content.trim() === "") {
                return Promise.resolve<void>(undefined);
            }
            if(!msg.author) {
                return Promise.resolve<void>(undefined);
            }
            if(eq && msg.content !== cmd) {
                return Promise.resolve<void>(undefined);
            } else if(!eq && !msg.content.startsWith(cmd + " ") && msg.content !== cmd) { 
                return Promise.resolve<void>(undefined);
            }
            if(f) {
                return f.call(f.caller, msg);
            } else {
                return Promise.resolve<void>(undefined);
            }
        };
        return descriptor;
    };
};

Funciona, mas na função real (f) this não persiste, então não há maneira de obter nada dele.

O que estou fazendo de errado e como recuperar this na minha função assíncrona?

@command("!ping", true)
async onMessage(msg:Message) {
    msg.react("🏃");
    let startDate = Date.now();
    msg = await msg.channel.sendMessage(":information_source: Pong!");
    let diff = Date.now() - startDate;
    // THAT'S THE POINT WHERE IT CRASHES
    this.log("info", `Ping for sendMessage in Channel#${msg.channel.id}: ${diff}ms`);
    msg.edit(`:information_source: Pong - \`${diff}ms\`!`);
}

Resposta #1

mude o descritor para ser uma função clássica e então você pode acessar o escopo diretamente de this. Além disso, se você mudar descriptor.value para ser uma função async, você pode usar await diretamente no decorador. https://stackblitz.com/edit/typescript-dycwcg

descriptor.value = async function(msg: Message) {
  await f.apply(this, msg);
}