Unable to call class methods inside its constructor - javascript

I'm struggling with the implementation of my express router (actually this is a "subrouter" of my main router, that's why I have to extends express.Router)
I have the following code (as an example I simplified it to have only one method) :
import express from "express";
export default class MandatoryFieldsSettingsRouter extends express.Router {
constructor() {
super();
this.get('/', this.retrieveMandatoryFieldsSettings);
}
async retrieveMandatoryFieldsSettings(req, res) {
//some treatment here
}
}
So in the file creating the main router of the application I can defined my subpath like so :
router.use('/mandatory-fields-settings', new MandatoryFieldsSettingsRouter());
I have the following error Error: Route.get() requires a callback function but got a [object Undefined] at application startup because this.retrieveMandatoryFieldsSettings is undefined inside the constructor.
I fixed it using this different method declaration :
// 1st impl : this one is the "wrong" one causing my error
async retrieveMandatoryFieldsSettings(req, res) {
//some treatment here
}
// 2nd impl : this one is the "good" one making my application working
retrieveMandatoryFieldsSettings = async function (req, res) {
//some treatment here
}
For some reason my company wants me to use the first implementation. Is there any way to use it and keep the way I declare my path inside my constructor ? (I think it's more readable to see every paths declared in the current class just by looking at its constructor).
My company isn't closeminded, if there is absolutely no reason to "ban" the second implementation just let me know and please explain what's the difference between the two if you know it (-> why the first got undefined and the second not ?)
Thanks !

You can use the first approach if you use the ES2020 syntax for private members (#):
async #retrieveMandatoryFieldsSettings(req, res) {
//some treatment here
}
Regards,
Craig

Related

Typescript - "this" undefined inside a non-arrow class method

I'm aware that the subject of "this" in both JS and TS has been covered by many questions, but I haven't been able to find an answer to the specific issue I'm facing. I'm certain that I'm just not understanding something basic and it's tricky to google for amongst the mountain of questions that boil down to arrow function scoping rules.
To preface, the code I'm struggling with is running on a Node back-end.
So, I've created a controller class with a method defined not as an arrow function (simplified for demonstration):
class UserController extends AbstractController {
constructor() { ... }
public async getUsers(x, y): Promise<any> {
return this.processRequest( ... ); //processRequest is a protected async definition on AbstractController
}
}
// ...
export default new UserController()
The issue I'm having is that this inside getUsers() is undefined, where I'd naturally expect it to be the instance of UserController it's executed on.
If I do convert getUsers to an arrow function...
class... {
public getUsers = async (x, y): Promise<any> => {
return this.processRequest( ... );
}
}
...then it works as expected.
I believe I understand how arrow function this captures work with regards to the surrounding scope; but in this case I feel like I'm missing two key understandings:
why does the first method not have any this? I feel like this should be the instance of UserController, and if not then at least it should be some more global object.
why does the second method work at all? There is no "surrounding scope" to capture this from - is there?
Here's how getUsers() is called:
import UserController from 'user.controller';
userRouter.get('/', authMiddleWare, UserController.getUsers);

Javascript/Express - Exports all methods vs exporting class containing methods

I am confused while encountering this over-looked question like how they are different ?
Module.exports = {
search_companies(req, res) {
//some ops
},
get_details(req, res) {
//some ops
}
};
vs
class MainContrller {
search_companies(req, res) {
//some ops
},
get_details(req, res) {
//some ops
}
}
module.exports.MainController = MainController;
The first one exports an object with the function search_companies and get_details. So you can call these to function on the object that is exported.
The second one exports a class MainController with the functions search_companies and get_details. Here you have to create an instance of MainController to be able to call those two functions on the instance.
You use the first syntax if you only need one instance of that object through the whole project. It's like a singleton or like static, but without the need to define an actual class for it.
And you use the second one if you need multiple different instances of MainController.
A module is supposed to be used like:
const { search_companies } = require('...');
A class is supposed to be used like:
const { MainController } = require('...');
const { search_companies } = new MainController();
MainController in this case is a bad practice because it mimics the usage of classes in other languages without taking the specifics of JavaScript into account.
MainController doesn't benefit from being a class if this instance is ignored and doesn't lose in functionality when a class is refactored to separate functions.
Classes aren't glorified namespaces in JavaScript; there are modules that already serve this purpose. If there's a need for a namespace and no need for class instance, a module can be used as a rule of thumb.

new object in constructor from class undefined

I'm creating a new object from a class in a constructor, and whenever it runs I get an error that operate is undefined in the method, though it is defined in the constructor. Operate itself is thoroughly tested and works great in a separate context so that's not the problem. I'm building it with Babel, not running it directly in Node 7.0.0
import Operate from "./operate"
export default class {
constructor(Schema) {
this.schema = Schema
this.operate = new Operate(this.schema)
console.log(this.operate.run) // <- Logs just fine
}
update(req, res) {
console.log(this.operate.run) // <- Nada
this.operate.run(req.body)
.then(value => {
res.status(200).json(value)
})
}
This feels like I'm missing something fundamental. I've heard this isn't a great pattern anyway, so please feel free to suggest a better way. Thanks so much in advance.
UPDATE: This is how update is being used. I don't suspect there's any problem here, as it has worked just fine when I had been importing controller as a function from another module, instead of a class
import {Router, } from "express"
import Controller from "../controller"
import User from "./user.model"
let controller = new Controller(User)
let router = new Router()
router.post("/", controller.update)
module.exports = router
Change from this:
router.post("/", controller.update)
to this:
router.post("/", controller.update.bind(controller))
When you pass controller.update it only passed a pointer to the method and any association with the controller object is lost. Then, when that update method is called later, there is no association with the appropriate object and thus the this handler in the method is wrong and you get the error you were seeing.
You either force the binding of the update method within the object or when you pass the method elsewhere that might not be called correctly, you can use the above structure to pass a bound version of the method.
You could also modify your definition of the update method to permanently bind it to your object in the constructor by adding this to the constructor:
this.update = this.update.bind(this);

Using ES6 classes OR Object Literals in controllers for an Express + NodeJS app

There are 2 things that I'm very confused about.
What is the advantage of using any of ES6 class or Object literals.
And where should I use any of them?
Some of the examples that I'm trying out are mentioned below. Please let me know when to use particular way of implementation and when not to.
Class Example 1:
// auth.js
class Auth {
login(req, res) {...}
signup(req, res) {...}
}
module.exports = new Auth();
// index.js
const auth = require('auth');
Class Example 2:
// auth.js
class Auth {
login(req, res) {...}
signup(req, res) {...}
}
module.exports = Auth;
// index.js
const Auth = require('auth');
const auth = new Auth();
Object Literal Example:
// auth.js
module.exports = {
login: (req, res) => {...},
signup: (req, res) => {...}
};
// index.js
const auth = require('auth');
What I think from reading about them is that:
Class Example 1:
You can not create more than 1 object. Because a module is only executed once. So, on every import you will get the same object. Something similar to singleton. (Correct me here if I misunderstood it)
You will not be able to access the static methods of the class because you are only exporting the object of the class.
Class Example 2:
If you have a class that contains nothing but helper methods and the object does not have any state, It makes no sense creating object of this class all the time. So, in case of helper classes, this should not be used.
Object Literal Example:
You can not do inheritance.
Same object will be passed around on every require. (Correct me if I'm wrong here as well)
Please help me understand these concepts, what I'm missing out, what I've misunderstood and what should be used when and where. I'll be very grateful for your help.
Feel free to edit the question, if you think I made a mistake somewhere.
Class Example 1: You can not create more than 1 object. Because a module is only executed once. So, on every import you will get the same object. Something similar to singleton.
Correct. This is an antipattern therefore. Do not use it. class syntax is no replacement for object literals.
You will not be able to access the static methods of the class because you are only exporting the object of the class.
Theoretically you can do auth.constructor.… but that's no good.
Class Example 2: If you have a class that contains nothing but helper methods and the object does not have any state, It makes no sense creating object of this class all the time. So, in case of helper classes, this should not be used.
Correct. Use a simple object literal instead, or even better: multiple named exports instead of "utility objects".
Object Literal Example: You can not do inheritance.
You still can use Object.create to do inheritance, or parasitic inheritance, or really anything.
Same object will be passed around on every require.
Correct, but that's not a disadvantage. If your object contains state, you should've used a class instead.
If your class has got a constructor, you can build several objects from this class threw :
var Panier= require('./panier');
var panier1 = new Panier(13, 12, 25);
var panier2 = new Panier(1, 32, 569);
Of course your Panier would be defined in the file Panier.js located in the same directory :
module.exports = class Panier
{
constructor(code, qte, prix)
{
this.codeArticle = code;
this.qteArticle = qte;
this.prixArticle = prix;
}
getCode()
{
return this.codeArticle;
}
getQte()
{
return this.qteArticle;
}
getPrix()
{
return this.prixArticle;
}
}

Flowtype: dynamically extending classes

Is it possible to manually define additional methods for an existing class?
My specific usecase is bluebird's promisifyAll() which:
Promisifies the entire object by going through the object's properties and creating an async equivalent of each function on the object and its prototype chain… http://bluebirdjs.com/docs/api/promise.promisifyall.html
Obviously, flow wouldn't be able to figure this out automatically. So, I'm willing to help it. The question is HOW?
Consider the following code
import http from 'http'
import { promisifyAll } from 'bluebird'
promisifyAll(http)
const server = http.createServer(() => { console.log('request is in'); })
server.listenAsync(8080).then(() => {
console.log('Server is ready to handle connections')
})
Flow gives the following error here:
property `listenAsync`. Property not found in
Server
There wouldn't be any error if I used listen. flow's smart enough to see that this is a real method defined in a module. But listenAsync is a dynamic addition by promisifyAll and is invisible to flow
That's not possible and that would not be really safe to do. Here is something you can do for your case:
first declare bluebird as following:
declare module "bluebird" {
declare function promisifyAll(arg: any): any
}
Then do this:
import httpNode from 'http'
import { promisifyAll } from 'bluebird'
import type { Server } from 'http'
type PromisifiedServer = Server & {
listenAsync(port: number, hostname?: string, backlog?: number): Promise<PromisifiedServer>;
};
type PromisifiedHttp = {
createServer(listener: Function): PromisifiedServer;
};
const http: PromisifiedHttp = promisifyAll(httpNode)
Here we manually cast http to type PromisifiedHttp. We still have to declare all promisifed types manually, although we can use type intersection to extends existing types.

Categories