The mistake occurs when attempting to access a class property generated by a class constructor, resulting in a type error due to reading properties of

I'm having trouble building an Express API in TypeScript using Node.js. I am new to Express and I have been learning Node, JavaScript, and TypeScript since 2022, so I apologize if the question is not too complex. The issue I'm facing is trying to build a class Controller that handles the necessary instructions for every route in my Express router. I am passing a DAO through the constructor that I have built to access the Firebase Firestore database. However, when I instantiate the object and try to run it, it gives me a "cannot read properties of undefined" error. Even though I found a solution using a closure, I want to learn how to do this using classes. Here is the code of the DAO:

 // Code for the DAO class goes here... 

And this is the code for the Controller class:

 // Code for the Controller class goes here... 

Thanks for your time. I'm trying to learn this beautiful world of backend development. I have tried various solutions to my issue, such as calling the constructor outside the class and passing the constant to the constructor, instantiating the DAO object as a parameter, and even calling the DAO constructor in a global variable and defining the properties. However, the only solution I found for my issue is transforming the class into a closure function and calling the constructor within the closure.

 // Error message and stack trace about 'dbManager' being undefined... 

Routes

 // Code for the routes definition and calling the readData method... 

Answer №1

const { fetchInfo, saveInfo, updateInfo, removeInfo } = new DataHandler('welcome')

You cannot destructure normally declared instance methods from classes.


Let's simplify this with an example:

class Bar {
    private info = "example"
    getInfo() { return this.info }
}

Calling getInfo in this format works:

const bar = new Bar()
console.log(bar.getInfo())
// example

However, if you destructure the method like this:

const { getInfo } = new Bar()
console.log(getInfo())
// Cannot read properties of undefined (reading 'info')

It will result in an error.

The issue arises because the value of this is lost when the method is deconstructed without the use of ., which provides the class instance to the function.


Let's consider another example:

class Bar {
    private info = "example"
    getInfo = () => { return this.info }
}

const bar = new Bar()
console.log(bar.getInfo())
// example

const { getInfo } = new Bar()
console.log(getInfo())
// example

In this case, TypeScript compiles property assignments in classes to occur in the constructor, and the arrow function => captures the value of this when it was declared. This allows for the method to be deconstructed and still function correctly.

It's important to note that while the traditional instance method declaration is shared among all instances, the arrow function method creates a new function for each instance. This may impact performance if a large number of instances are created, but for backend service classes like this, it's typically not a concern.


In your scenario, simply call the method on the instance:

const handler = new DataHandler('welcome')
router.get('/', (req, res) => handler.fetchInfo(req, res))

Alternatively, declare your method as an arrow function.

export class DataHandler {
  //...
  fetchInfo = async (req: Request, res: Response): Promise<void> => {
    const id: string = req.params.id
    if (id !== undefined) {
      res.send(await this.dbManager.getById(id))
    } else {
      res.send(await this.dbManager.getAll())
    }
  }
  //...
}

const { fetchInfo } = new DataHandler()
fetchInfo() // should work now

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for displaying the data on top of individual column bars: Hightcharts, Vue-chartkick, and Cube Js

Looking for assistance with adding value labels to the top of each column bar in a Vue chart using chartkick and highcharts. https://i.sstatic.net/c4Bwc.jpg Check out the image above to see my current output. <template> <column-chart lable= ...

Utilizing mailerlite popups within a Next.js application: A step-by-step guide

Trying to include a mailerlite popup in a client's next.js project has been quite challenging for me. I am struggling to convert the JavaScript snippets into jsx in order to make the popups work smoothly. Everything seems to function properly on initi ...

The 'payload' property is not found within the 'Actions' type

I recently started using TypeScript and Visual Studio Code. I encountered the following issue: *[ts] Property 'payload' does not exist on type 'Actions'. This is my code: action.ts file: import { Action } from '@ngrx/store&apos ...

Exploring the contrast of app.use and app.get *within the realm of proxy servers*

Seeking clarification on the distinction between express's app.get() and app.use(). I am aware that app.use is applicable to all HTTP verbs. According to sources, "app.use() adds middleware instead of a route" I am curious about why this particular ...

What is the best way to open a page in a new tab within the row command event of a gridview?

Here is the code snippet I am working with: protected void gv_inbox_RowCommand(object sender, GridViewCommandEventArgs e) { int index = Convert.ToInt32(e.CommandArgument); if (e.CommandName == "sign") { Session["TransYear"] = int.Pars ...

Modifying a $scope variable beyond the controller in AngularJS

I am trying to update a variable called $scope.outsidescope outside of the controller in my AngularJS application. The routing is done using $routeProvider, and the $scope.outsidescope variable is located outside of the ng-view. My query is how can I modi ...

Load Vue dynamically to implement reCAPTCHA script

I am looking for a way to dynamically load a script like recaptcha specifically within the Register.Vue / login.Vue component. <script src="https://www.google.com/recaptcha/api.js?onload=vueRecaptchaApiLoaded&render=explicit" async defer> </s ...

Having trouble getting req.files to work in a Node.js Express application?

Hello there, I'm facing an issue with accepting an uploaded file. Every time I call req.files, it comes out as undefined. I can't seem to figure out what I am doing wrong... Below is a snippet of my app.js file: var express = require('expr ...

What is the C sharp version of this code structure?

I'm curious to know what the C# syntax is for declaring a property like this: filters: { [arg: string]: string }; ...

Is it possible to trigger an event for only one connected client instead of broadcasting it to all clients using socket.io?

I am seeking a way to send an event to just one connected client, rather than broadcasting it to all clients using io.emit(). ...

Error: The import token is not what Express was expecting

In my index.js file, I have the following code: import express from 'express' import data from './data/data' const app = express(); const PORT = 3000; app.listen(PORT, () => console.log(`Server is running on ${PORT}`) ); Be ...

Achieving the extraction of a particular string from an HTML element using JavaScript

<input id="WD01B3" ct="CB" lsdata="{2:'WD01B4',4:'Any',20:'\x7b\x22WDA_TYPE\x22\x3a\x22DROPDOWN_BY_KEY\x22,\x22WDA_ID\x22\x3a\x22ABCA950297D2C0C432BAB9BB ...

Deselect the DOM element

Here is a jQuery code snippet: $(document).ready(function () { $(".story-area > h1, .story-area > p, .story-area > div > p").text(function () { return convertString($(this).text()); }); }); Additionally, there is a function de ...

Axios: Exception handling does not involve entering the catch method

Implementing a function to adjust a contract name involves making an axios request to the backend API using a specific ID. Upon each execution, a sweetalert prompt is displayed. axios({ url: '/api/contract/' + id, method: 'put ...

Adding to an existing array in MongoJS

I have been attempting to append data to an existing array in my mongoDB. The code snippet below is what I currently have, but unfortunately, it does not work as expected since all the existing data gets wiped out when I try to add new data: db.ca ...

Eliminate the ArrayOfObjects by filtering out the items with a specific ID

Here is an array of objects I've named mycart[]: [{"id":"6","quantity":"20","price":1500,"title":"casual blue strip"}, {"id":"10","quantity":"2","price":1500,"title":"casual blue round neck"},{"id":"5","quantity":20,"price":150,"title":"casual ...

I'm having trouble figuring out how to calculate total expenses by category using sequelize

Currently, I am working on my expense-tracking application. The database consists of three tables - User, Expense, and Category. Each Expense model includes fields like name, date, categoryId, and amount. To interact with the data, I have set up a REST API ...

After adding data to an empty array, index 0 becomes undefined for someEmptyArray

Currently, I am utilizing fs.readdir to generate an array of filenames within a specific directory. Additionally, I have implemented some regex functions to filter out undesirable filenames and/or filetypes. Upon executing the code provided below, I succe ...

Refreshing the PHP variable without needing to refresh the page

Recently, I've delved into the world of JSON and PHP programming. I am currently working on a web page that displays data from a file called file.py. This data is intended to be visualized on a gauge that updates every second. var gauge1; var x = ...

Issue: Attempting to write data after reaching the end in Node.js while using

I have encountered the following error: Heading Caught exception: Error: write after end at ServerResponse.OutgoingMessage.write (_http_outgoing.js:413:15) at ServerResponse.res.write (/home/projectfolder/node_modules/express/node_modules/connect/lib/mid ...