The TypeScript abstract class error occurs when attempting to access the 'routes' property of an undefined object

Currently, I am working on creating a server using express.js and typescript. In my project, I have an abstract class called Controller which serves as the base class for all controllers. Additionally, I have a specific class named AuthController that manages authentication logic. However, when I attempt to send a POST request to the server, I encounter an error message:

TypeError: Cannot read property 'routes' of undefined
    at setRoutes (C:\path\to\project\dist\typings\Controller.js:12:34)
    at Layer.handle [as handle_request] (C:\path\to\project\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (C:\path\to\project\node_modules\express\lib\router\index.js:317:13)
    ...

Here is a snippet from my tsconfig file:

{
    "compilerOptions": {
    "target": "es6",                   
    "module": "commonjs",                    
    "outDir": "./dist",                        
    "noEmitOnError": true,
    "strict": true,                           
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  }
}

Abstract controller class:

export default abstract class Controller {
    public router: Router = Router();
    public abstract path: string;
    protected abstract routes: Array<IRoute> = [];

    public setRoutes(): Router {
        // Route handling logic here
    }
};

Route interface:

export interface IRoute {
    // Interface structure
};

Auth controller class:

export default class AuthController extends Controller {
    // Class implementation
}

To utilize these controllers in the Server class, I follow this approach:

public loadControllers(controllers: Array<Controller>): void {
    // Loading controller logic here
};

Finally, I initialize the controllers in app.ts like so :

const controllers: Array<Controller> = [
    new AuthController(),
    new OtherController(),
];
server.loadControllers(controllers);

Answer №1

Within the function loadControllers, the setRoutes method is bound as a callback for an express handler. It's uncertain when and by whom the callback function will be called, typically in this context (who calls the express handler function) it is undefined. This is why the this.routes results in a

TypeError: Cannot read property 'routes' of undefined
error.

I believe there are 2 ways to address this problem:

  1. Binding the this context for the setRoutes method (recommended): within the loadControllers function.
this.app.use(controller.path, controller.setRoutes.bind(controller)); // binding controller as `this`
  1. Utilize arrow functions to "fix" the scope of the this keyword: in an abstract controller class
public setRoutes = (): Router => { // Now, setRoutes is a property
    // method content
    // Now, "this" always refers to this controller
}

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

How come the splice method is changing the value of the original object?

There's something strange happening with this code I'm trying out. Code: const x = [{ a: 'alpha', b: 'beta' }, { a: 'gamma' }]; const y = x[0]; y.a = 'delta'; x.splice(1, 0, y) console.log(x) Output: [ ...

Properties around the globe with Express & Handlebars

Currently, I am utilizing Handlebars (specifically express3-handlebars) for templates and Passport for authentication in my NodeJS application. Everything is functioning smoothly, but I have been contemplating if there is a method to globally pass the req. ...

Expressing emotions through face paint, opt for using props over media queries

Currently working on a project with emotion, I am interested in utilizing the facepaint library for face painting as shown below: const mq = facepaint([ this.layout === 'center', this.layout === 'left' ]) css(mq({ display: [&a ...

Receiving the error "Potential null object. TS2531" while working with a form input field

I am currently working on developing a straightforward form to collect email and password details from new users signing up on Firebase. I am utilizing React with Typescript, and encountering an error labeled "Object is possibly 'null'. TS2531" s ...

What could be causing the django request.query_params to be undefined?

Within the index page of next.js, I have the following request in the getServerSideProps function: export const getServerSideProps = wrapper.getServerSideProps( async (context) => { const { store, query } = context; if (!query.page) { qu ...

The selected image should change its border color, while clicking on another image within the same div should deselect the previous image

https://i.sstatic.net/jp2VF.png I could really use some assistance! I've been working on Angular8 and I came across an image that shows how all the div elements are being selected when clicking on an image. Instead of just removing the border effect f ...

Transforming class attributes in Typescript

I am facing a situation where I need to alter the type of a variable that stores an object based on certain conditions. Here is the variable in question: class MyClass { public referrers: SelectItemGroup[]; } The issue arises when I only need to add a ...

Show a condensed version of a lengthy string in a div using React TS

I've been tackling a React component that takes in a lengthy string and a number as props. The goal of the component is to show a truncated version of the string based on the specified number, while also featuring "show more" and "show less" buttons. ...

Unusual problem arises with scoping when employing typeguards

Consider the following TypeScript code snippet: interface A { bar: string; } const isA = <T>(obj: T): obj is T & A => { obj['bar'] = 'world'; return true; } let obj = { foo: 'hello' }; if (!isA(obj)) thro ...

The ngModel directive is present here

In my Angular project, I've observed the use of two different syntaxes for binding ngModel: [(ngModel)]="this.properties.offerValue" and [(ngModel)]="properties.offerValue". Although they appear to function identically, it has sparked my curiosity ab ...

MatTableDataSource failing to showcase remote dataSource in mat-table component

I am experiencing issues while trying to incorporate a component using mat-table with data source from a Remote Server. The table is not displaying the data as expected. html <div class="mat-elevation-z8"> <mat-form-field> <input ...

Sending POST Requests with Next.js Version 14

How can I send a POST request using axios in Next.js 14, I prefer axios but fetch is also okay. I have been getting an AxiosError: Network Error when I try to use axios and TypeError: fetch failed when using fetch. However, it works fine with Postman. I ...

Angular-template static functions refer to functions that do not require an

Our project utilizes the linting-config provided by AirBnB. There is a rule that stipulates class methods must utilize this or be declared as static. While this rule theoretically makes sense, it seems to present challenges within an angular context. Consi ...

Upgrading from Angular 5 to 6: Embracing the RxJS Changes without the crutch of rxjs

Currently, I am facing the challenging task of migrating a project from Angular 5.2.11 to version 6.0.0. The main issue I'm encountering is with RxJS 6 (which is essential for Angular versions above 6). Here's an example of one of the errors that ...

Error: "Headers could not be modified after they have been sent."

Recently, I've been delving into the world of nodejs and its routing system. However, I've encountered a perplexing issue that only seems to arise in production mode on Heroku - "Can't set headers after they are sent." This problem doesn&apo ...

Is type checking performed after compiling a TypeScript file?

Currently working on a web server project with nest.js! Here's a snippet of code from my controller file: @Delete('users/:id/courses/:course_id') deleteUserCourses( @Param() { id, course_id }: { id: number; course_id: string }, ) ...

Having trouble locating the name 'BigInt64Array'? Perhaps it's time to consider switching your target library. You might want to update the 'lib' compiler option to 'es2020' or a later version

I've completed all the necessary steps and included dependencies, yet I encounter an error when building the project: projects/fs-lib/node_modules/type-fest/source/typed-array.d.ts:16:4 - error TS2583: Cannot find name 'BigInt64Array'. It su ...

Creating an entry at the beginning of a MongoDB database using Express

My mongoDB database holds a collection of items: [{"_id":"0", "a": "b"}, {"_id":"1", "a": "c"}] When adding a new item to the database with a POST request, I utilize Express r ...

Rapid routes

Currently, I am working on developing a content preprocessor using NodeJS I have come up with 3 specific methods of preprocessing: generating html producing xhtml creating xml Each method requires different middleware, making them distinct from one anot ...

Tips for efficiently handling state across various forms in separate components using only one save button within a React-Redux application

I am currently developing an application that combines a .NET Core backend with a React frontend, using React Hook Form for managing forms. Unlike typical single-page applications, my frontend is not built in such a way. On a specific page of the applicat ...