Augmenting existing interfaces - node.js

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

Related

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.

When does session property (express session data object) gets added to request object when using express-session middleware?

When I use express-session middleware, when does the session property in request object(request.session) gets available?
Does it always stay available since the beginning when the server starts? when no session is made (no login) then session data is empty but session property itself is always available on request object. Is is this case? OR
does session object gets attached to request only when someone logs in? and when no user is logged in then request.session is always undefined . is it this?
The intention of this question is to know which, in typescript, out of the follow two type definition I have to use:
(one is using session? and in another session is used)
import { SessionData } from "express-session";
declare module "express-session" {
interface SessionData {
userId: string;
}
}
export interface MyContext {
session: SessionData;
}
OR
import { SessionData } from "express-session";
declare module "express-session" {
interface SessionData {
userId: string;
}
}
export interface MyContext {
session?: SessionData;
}
After long waiting I got the answer in Ben Awad discord channel.
Here it is
Session middleware is always defined, if no session exists on the request it'll return an empty object.
So the option-1 type definition is right, i.e.,
import { SessionData } from "express-session";
declare module "express-session" {
interface SessionData {
userId: string;
}
}
export interface MyContext {
session: SessionData;
}

How to get FullURL with NestJS?

How do I get the full URL of the page that NestJS is processing?
(e.g. http://localhost:3000/hoge)
//
// If you implement it with express, it looks like this.
// e.g. http://localhost:3000/hoge
//
function getFullUrl(req: express.Request) {
return `${req.protocol}://${req.get('Host')}${req.originalUrl}`;
}
You can inject the request-object using the Req() decorator allowing you to do pretty much the same thing you did in your pure express-app.
import {Controller, Get, Req} from '#nestjs/common';
import {Request} from 'express';
#Controller()
export class AppController {
#Get()
getHello(#Req() req: Request): void {
console.log(`${req.protocol}://${req.get('Host')}${req.originalUrl}`);
}
}
This of course assumes that you're using Express as your http-adapter (which is the default).

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;
});

extending express application interface

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.

Resources