extending express application interface - node.js

I am trying to extend the expressjs Application interface using declaration merging as explained in the express type definitions
declare module Express {
// These open interfaces may be extended in an application-specific manner via declaration merging.
// See for example method-override.d.ts (https://github.com/borisyankov/DefinitelyTyped/blob/master/method-override/method-override.d.ts)
export interface Request { }
export interface Response { }
export interface Application { }
}
So, my app.ts looks like this:
/// <reference path="typings/express/express.d.ts" />
declare module Express {
export interface Application {
testA: string;
}
export interface Request {
testR: string;
}
}
import express = require('express');
var app = express();
app.testA = "why not?";
app.use(function (req, res, next) {
req.testR = "xxx";
})
I get the errors:
"Property testA does not exist on type Express"
"Property testR does not exist on type Request"
Any clues?

Since you are using modules, declaration merging won't happen here. In app.ts there isn't an Express module to merge with so it's making a completely separate module definition. You need to move the code...
declare module Express {
export interface Application {
testA: string;
}
export interface Request {
testR: string;
}
}
...into a .d.ts file so that the interfaces are merged with the ones in express.d.ts.

Related

Express middleware with TS: void' is not assignable to parameter of type 'PathParams'

I'm new to typescript and converting my existing JS application. I'm stuck on what seems simple and I've tried searching existing posts to no avail.
I have a simple middleware in Express to log all requests:
const { logger } = require("winston");
import express, { Application, Request, Response, NextFunction } from 'express'
...
const app: Application = express();
...
// Middleware - Log all http requests
app.use((req: Request, res: Response, next: NextFunction) => {
logger.info(`${req.loggedInUser} user [${req.originalUrl}]`) ;
return next();
});
In typescript this errors with
The last overload gave the following error.
Argument of type '(req: Request, res: Response, next: NextFunction) => void' is not assignable to parameter of type 'PathParams'.
If it matters I've extended the Request object in index.d.ts:
declare module "express" {
export interface Request {
user: any;
loggedInUser: any;
oidc: any;
}
}
The logger is winston.
Things I've tried:
setting the output type of the function to void - didn't work.
adding "as express.RequestHandler" after logger similar to Express errors with typescript but no luck.
changing Request to type "any" - works but that of course is a poor workaround.
Adding path argument "/" - doesn't work thought the IDE (VSCode) no longer reports as an error. Compile fails though.
How can I fix this and what is the concept behind this?
Most express docs show using "app.use" without the path for things like helmet, cors etc so it seems like this should be common.
Thank you for your insights!
Try extending the Request object like this instead
declare global {
namespace Express {
interface Request {
user: any;
loggedInUser: any;
oidc: any;
}
}
}
as mentioned by basarat here: Extend Express Request object using Typescript.
I replicated your error message with my express app using your Request object extension and changing it to the above code fixed the issue.

How to declare variable of type Express in TypeScript without importing express?

I have main file called main.ts where I imported express with
import express from 'express';
Then I have another class in separate file where I want to create method "init" which has one parameter named "app" of type Express. But somehow i can't say app:Express without importing express.
My goal is to import express only once and keep it in a main.ts file, and then in a main.ts file I will call "init" method ( from a separate file) where I will pass that imported express.
Main.ts file
import express from 'express';
import { FriendsRouter } from './routes/friends.router';
const app = express();
FriendsRouter.init(app);
const PORT:number = 3000;
app.listen(PORT,()=>{
console.log('Listening at '+PORT);
})
Spearete file (friends router in my case)
export class FriendsRouter {
private constructor(){
}
public static init(app:Express): void{
app.get('/friends',someMethod);
}
}
Problem is, in FriendsRouter file, I can't say app: Express.
How can I fix this ?
The usual thing is to import the type Express from the express package:
import { Express } from "express";
Note that that's just importing the type, not the function. The rest of your code is then fine as-is (including the type on app).
If you don't have that type, install the types for express like this:
npm install --save-dev #types/express
...but you've probably already done that.

TypeORM Connection "default" was not found when using a routes file and repository pattern

I have a TS project where I'm using TypeORM. I'm using Repository pattern so I have layers: Controller -> Service -> Repository.
The Controller constructor initialize the Service class which initialize Repository class, where the constructor is:
constructor(){
this.ormRepository = getRepository(TypeormEntity)
}
This works fine when I create the routes in the index.ts like this:
createConnection().then(() => {
const controller = new MyController()
app.get('/', controller.getSomething);
})
The connection is created and then I initialize the class using new MyController().
The problem is when I want to get the routes in another file. I want to get this structure folder:
src
|--> index.ts
|--> routes
|--> v1
|--> router.ts
|--> value
|--> value.route.ts
|--> v2
|--> ...
So, to achieve this, the index.ts import the routes. But the problem is, as the import is done, the MyController() constructor is executed and the execution fails.
So I want to have something like this in index.ts
import * as express from 'express'
import { createConnection } from "typeorm";
import Router from './routes/v1/router'
const app = express()
createConnection().then(() => {
app.use('/', Router)
app.listen(port)
})
Also, following the import call, the file router.ts in routes/v1 is:
import { json, Router } from 'express'
import valueRouter from './value/value.route'
const router = Router()
router.use(json())
router.use('/value', valueRouter)
export default router
This is to add a "prefix" to all routes depending the resource they call.
And value.route.ts is where the controller is initialized and fails.
import { Router } from "express";
import ValueController from '../../../controller/value.controller'
const router = Router()
const vc = new ValueController()
router.get('/',vc.getSomething)
export default router
I've tested deleting the constructor and the project intializes ok, so the problem is the repository initialization accross Controller & Service.
How can I achieve this?
Thanks in advance.
Finally I solved my own issue using dynamic imports.
Now my index.ts looks like this:
createConnection().then(() => {
import('./routes/v1/router').then((router: any) => {
app.use('/', router.default)
app.listen(port)
})
})
Which I think is much cleaner than having all routes added in this file. Calling routes in an external file I can manage a huge amount and maintain a clean structure.

Why in DefinitelyTyped `http.IncomingMessage` defined as interface, not a class?

As said documentation of Node.js, http.IncomingMessage is a class, not an interface. So why in DefinitelyTyped http.IncomingMessage defined as interface?
Now in my code I can not do this:
import * as http from 'http';
let Request = http.IncomingMessage;
TypeScript error:
[ts] Property 'IncomingMessage' does not exist on type 'typeof "http"'.
I'm doing something wrong?
I see that really not exists Node.js API for extends http.IncomingMessage. This way more as hack and not normal extends:
http.IncomingMessage.prototype.absoluteUri = function absoluteUri(path) {
// ...
};
I found this answer to extends http.IncomingMessage:
var extendedRequest = {
get userAgent() {
this.request.headers['user-agent'];
}
}
createServerCallback(function (req, res) {
var request = Object.create(extendedRequest);
request.request = req;
});

Augmenting existing interfaces

This isn't a specific koa question even though all the code is using koa, I'm just new to node and the module system.
When using Koa every request is defined by the Request interface:
declare module "koa" {
namespace Koa {
...
export interface Request {
...
}
...
}
...
namespace Koa {}
export = Koa;
}
I'm using the bodyparser middleware so Request has a property named body but typescript is unaware of this and so I'm trying to add that by adding this definition file as a reference:
/// <reference path="globals/koa/index.d.ts" />
/// <reference path="koa.d.ts" />
import koa = require("koa");
...
app.use(ctx => {
console.log(ctx.request.body); // error: Property 'body' does not exist on type 'Request'
});
Where koa.d.ts is:
declare module "koa" {
namespace Koa {
export interface Request {
body: any;
}
}
export default Koa;
}
But this is probably the wrong way to do it as it's not working.
How can it be done?
Thanks.
I just had to work through this. I added this to my custom-typings.d.ts:
import {Request} from "koa";
declare module "koa" {
interface Request {
body: any;
}
}
Just ran into this. I found that since I was using koa-bodyparser middleware, I needed to install the #types/koa-bodyparser module which augments the interface for you - https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/koa-bodyparser/index.d.ts#L20.
import * as bodyparser from 'koa-bodyparser';
...
app.use(bodyParser());
Then, in your route, "body" will be available on the request object.
ctx.request.body

Resources