Tengo la siguiente función para recuperar un objeto de una base de datos y extraer una URL:
async redirect(id: string, redirectFunction: Function) { if (!IdExists(id)) { throw new Error(`ID ${id} does not exist.`); } const redirectLocation: string = await prisma.url.findUnique({ where: { uniqueId: id }, select: { url: true }, }).then((data) => { return data?.url!; }); redirectFunction('http://' + redirectLocation); }La función se llama en el siguiente segmento de código:
app.get('/:id', async (req, res) => { try { redirectController.redirect(req.params.id, res.redirect); } catch (error) { console.error(error); } }); Sin embargo, obtengo TypeError: Cannot read properties of undefined (reading 'location') , veo que el error está relacionado con el método res.redirect . Sin embargo, cuando lo reemplazo por console.log para la depuración, la URL se muestra correctamente. ¿Qué puede estar causando este error?
Esta línea de código:
redirectController.redirect(req.params.id, res.redirect); Pasa res.redirect (una referencia de función) como segundo argumento, pero todo lo que se pasa es solo la función, por lo que res se pierde cuando intenta llamarlo más tarde. Eso hace que el método tenga this valor incorrecto cuando se ejecuta y muchas cosas salen mal.
Puedes arreglar eso de varias maneras diferentes. Una vez de esa manera es con .bind() :
redirectController.redirect(req.params.id, res.redirect.bind(res)); .bind() crea una pequeña función de código auxiliar que recuerda el valor de res para que cuando se llame a la función de código auxiliar, se llame con la referencia de res correcta y, por lo tanto, this valor dentro de la función será correcto.
Otra forma de resolverlo es crear tu propia pequeña función auxiliar:
redirectController.redirect(req.params.id, (...args) => { res.redirect(...args); }); Cuando llama a su función de código auxiliar, llama a res.redirect() correctamente y le pasa los argumentos con los que el controlador llamó a su función de código auxiliar.
Como pequeña demostración, puedes ver este efecto aquí:
const obj = { greeting: "Hello", talk: function() { if (this && this.greeting) { console.log(`this.greeting is "${this.greeting}"`); } else { console.log("value of this is wrong"); } } } console.log("calling as obj.talk()"); obj.talk(); // works console.log("-------------------------"); // function we pass a method to and then call that method function callTalk(fn) { fn(); } console.log("calling by passing method to another function"); callTalk(obj.talk); // doesn't work // call it using .bind() console.log("-------------------------"); console.log("calling using .bind()"); callTalk(obj.talk.bind(obj)); // works