Declaration merging and aliasing not working together - node.js

I recently started converting my node.js/express application to typescript.
It is working great so far, but there are some things I am not sure of:
I noticed that in the sample project by Microsoft, they are inconsistent with their typing.
app.ts
app.get('/findImages', function(req, res) {
// ...
}
routes/index.ts
export function index(req: express.Request, res: express.Response) {
// ....
};
As you can see they are sometimes defining types, sometimes not. I noticed that there is no IntelliSense in the first case, but this might also be an issue of IntelliJ. What would be the best practice here?
At first I thought I would just type everything, but then I noticed another odd behaviour:
app.ts
/// <reference path="connect-flash/connect-flash.d.ts" />
/// <reference path="express-session/express-session.d.ts" />
/// <reference path="express/express.d.ts" />
/// <reference path="passport/passport.d.ts" />
import express = require('express');
import session = require('express-session');
import passport = require('passport');
import flash = require('connect-flash');
var app: express.Express = express();
// Express without capital letter
route.get('/', function (req: express.Request, res: express.Response): void {
req.flash('message'); // no IntelliSense
var session = req.session; // no IntelliSense
var ip = req.ip; // works
var test = req.params.test; // works
});
// Express with capital letter
route.get('/', function (req: Express.Request, res: Express.Response): void {
req.flash('message'); // works
var session = req.session; // works
var ip = req.ip; // no IntelliSense; compile error TS2339
var test = req.params.test; // no IntelliSense; compile error TS2339
});
I am getting the following errors:
Error:(54, 22) TS2339: Property 'ip' does not exist on type 'Request'.
Error:(55, 24) TS2339: Property 'params' does not exist on type 'Request'.
I was looking through the definition files and noticed that there are apparently two different ways to define a module:
express.d.ts
declare module Express {...}
declare module "express" {...}
I tried multiple combinations of upper and lower case (also in the other definition files) with no success.
It seems that there are two separate definitions of the express module. The first one is also present in other modules such as express-session.d.ts or connect-flash.d.ts, and they are merged together correctly. But there seems to be a problem with the upper and lower case difference in the express.d.ts file. Is there a way to merge them?
Thanks for your help.

As you can see they are sometimes defining types, sometimes not. I noticed that there is no IntelliSense in the first case, but this might also be an issue of IntelliJ. What would be the best practice here
I try to be explicit everywhere. But you can avoid this if typescript can infer it for you.
I am getting the following errors:
If ip is a part of the express request then that's just an omission in the express.d.ts that needs to be fixed.
noticed that there are apparently two different ways to define a module:
These the two different kind of modules. declare module foo means that is a global variable foo available. declare module "foo" means you can do import foo = require('foo').
But there seems to be a problem with the upper and lower case difference in the express.d.ts file. Is there a way to merge them
They should all have the same case.

Related

Typescript syntax related

I am starting to develop applications using typescript. I had come across a code snippet where I couldn't understand the line marked within ** <> **. Anybody please throw some light.
export const applyRoutes = (routes: Route[], router: Router) => {
for (const route of routes) {
const { method, path, handler } = route;
**(router as any)[method](path, handler);**
}
};
Regards,
Karthikeyan R
(router as any) tells typescript that regardless of what it thinks the types are, it should treat router as having type any. In other words, it turns off type checking.
router[method](path, handler) means "access the method property on router, then call it passing in path and handler".

module.exports = ({}) vs {}

I work with Koa middleware and in some code I use this code in router:
module.exports = ({router}) => {
//some code
}
if I do:
module.exports = {router} => {
//some code
}
the nodejs app throws an error. So whats the difference between these two different exports except the error part?
{(router)} is just wrong. You should see module.exports as a function so it has () where the arguments go, which in this case is an object {} of the functions you want to export (here router, but it could be multiple just as well.
I think this article gives a very clear explanation: https://www.sitepoint.com/understanding-module-exports-exports-node-js/

In Node, why does 'require' assignment sometimes require curly brackets?

Running some tests through Chai, I noticed the tests would fail under this code:
const add = require('./addition');
//'add is not a function error' even though it's directly exported as a function
But it would pass under this:
const {add} = require('./addition');
Yet when using npm modules, everything is declared without the brackets:
var express = require('express');
var app = express();
var session = require('express-session');
And those are essentially objects with multiple properties to be accessed. Why does it work this way? Is it only function exports that must be assigned as objects explicitly?
This is known as object destructuring. Please refer the link.
For example you have exported a file called sampleFunctions.js which has following functions as exports
function function1(params) {};
function function2(params) {};
module.exports = {
sampleFunc1: function1,
sampleFunc2: function2
}
Now when you need to require it, there are two ways -
when you only need one function(using object destructuring)
let {sampleFunc1} = require('./sampleFunctions');
sampleFunc1();
In this you exposed only the required function not all of the functions exported from that file.
when you want to require all the functions from that file
let sampleFuncs = require('./sampleFunctions');
let samFunc1 = sampleFuncs.sampleFunc1;
samFunc1()

Using express-validator typescript definitions

I'm trying to convert some of my code to TypeScript, but having problems with express-validator definitions
My code looks like this:
///<reference path='../../../d.ts/node.d.ts' />
///<reference path='../../../d.ts/express.d.ts' />
///<reference path='../../../d.ts/express-validator.d.ts' />
import express = require('express');
import validator = require('express-validator');
function validate(req: express.Request, res: express.Response) {
req.assert('name', 'Name is required').notEmpty();
var errors = req.validationErrors();
if (errors !== null && errors.length > 0) {
res.json({
result: false,
errors: errors
});
return false;
}
return true;
}
Typescript compiler generates following errors:
error TS2094: The property 'assert' does not exist on value of type 'express.Request'.
error TS2094: The property 'validationErrors' does not exist on value of type 'express.Request'.
Which makes sense especially looking at the expreess-validator definition
export interface RequestValidation {
check(field: string, message: string): Validator;
assert(field: string, message: string): Validator;
sanitize(field: string): Sanitizer;
onValidationError(func: (msg: string) => void): void;
}
My understandment of RequestValidation interface is it must extend express.Request interface, but modifying this interface declaration does not really help.
I'm I doing something wrong?
Thank You!
It looks to me like the Express Validator library extends the Express Request object. i.e. it adds additional methods to the existing Request defined in Express.
Disclaimer: I haven't been able to find any good documentation for the Express Validator library and if someone has a link I can be more exact.
With this in mind, if the Express Validator library extends the Express Request interface, the definition should reflect this. Here is an example that extends the definitions for Express and Express Validator on Definitely Typed.
declare module Express {
interface Request extends ExpressValidator.RequestValidation {
}
}
This will solve the issues with assert, for example - if someone finds some documentation I expect the validatonErrors issue can be solved in a similar way.
I have a helper function that checks for the 'id' param on the request object. The declaration that works correctly on TypeScript 1.5.0-beta is:
// Somewhere at the top of your TypeScript code
/// <reference path="../../../../typings/tsd.d.ts" />
import ExpressValidator = require('express-validator');
import util = require('util');
And the helper function that I use:
function getOnePreconditions(req:ExpressValidator.RequestValidation, res:express.Response, next:Function) {
req.checkParams('id', 'Parameter Id is mandatory').notEmpty().isInt();
var errors = req.validationErrors();
if (errors) {
res.send(400, 'errors' + util.inspect(errors));
} else {
next();
}
}
If you do have tsd.json defined for the project and you are correctly referencing to the *.d.ts TypeScript definition files in your code, then definitely add the declaration file for express-validator by using:
tsd install express-validator --save

How to avoid memory conflicts on ExpressJS/Node.js

I'm using Express and Passport for node.js to build a simple web server, I coded a simple module and then I loaded the module inside a GET request, everything works great until more than one user access the request.
I use to believe that a "var" inside an "app.get" function was removed from memory after the function finished, but isn't the case, I use some local variables inside the external module and the values are being shared between users, the module looks like this:
var some_value=0;
function some_method(){
some_value++;
return some_value;
}
exports.some_method = some_method;
And the Express request code looks like this:
app.get('/someurl', function(req, res) {
var some_extermal_module = require('/some_extermal_module'); // <-----Right way?
var data = some_extermal_module.some_method();
res.render('view', {
title : 'Title',
data_to_vew: data
});
});
An object inside a "app.get" request stays always in memory regardless of is being accessed by a different user?
How to clean a "var" object after it runs?
How can I avoid this memory conflicts?
Do I have to code differently the module or call differently the module?
Thanks a lot.
UPDATE: I guess this is a proper solution but I need the review of some node.js/Express expert for approval it or correction.
app.js:
var ext_mod = require('./module');
var express = require('express');
var app = express();
app.get('/', function(req, res){
var ex_mod_instance = new ext_mod({});
ex_mod_instance.func_a({},function(ret){
res.send('Hello World: '+ret);
});
ex_mod_instance = null; // clean
});
app.listen(8080);
console.log('Listening on port 8080');
module.js:
var node_module = function(config) {
this.config = config;
this.counter=0;
};
node_module.prototype = {
func_a: function(param,done) {
this.counter++;
done(this.counter);
},
func_b: function(param,done) {
}
};
module.exports = node_module;
Is this the best way to save memory (leaks)?
Every time a function is called you do get "clean" local variables in the local scope. Modules are for the purpose of writing clean, organized code, so that you do not have every function and variable in the global scope. I believe require does cache the module, so maybe you are having a problem with variables in the closure around the function exported from the module. You'll have to include more code.
One way you could solve this is by exporting a function that creates the module. That function could be your constructor, which will scope your counter locally.
Again, this is one solution.
Your variable 'some_value' is global in the context of the module. So each time a request use this module, it uses the same variable.
(Require does cache the modules wich are loaded only the first time)
I can think of 2 ways to achieve this:
either you want one variable per request, and you declare this variable in the module function, or in the res.locals.some_value if you want to use it in many functions during the same request
either you want one variable per user, and then you need to use express session middleware, and add the variable to req.session.some_value

Resources