i cannot declare new property in request object of express - node.js

I'm trying to attach the new property to the request object in typescript.
this is the code :
import { request, Request, response, Response } from "express";
((req: Request, res: Response) => {
console.log(req.user);
})(request, response)
i'm declaring like this :
declare global {
namespace Express {
interface Request {
user: string;
}
}
}
and then I'm running it with ts-node. result is :
/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:843
return new TSError(diagnosticText, diagnosticCodes, diagnostics);
^
TSError: тип Unable to compile TypeScript:
x.ts:9:21 - error TS2339: Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
9 console.log(req.user);
~~~~
at createTSError (/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:843:12)
at reportTSError (/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:847:19)
at getOutput (/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:1057:36)
at Object.compile (/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:1411:41)
at Module.m._compile (/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:1596:30)
at Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
at Object.require.extensions.<computed> [as .ts] (/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:1600:12)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:827:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12) {
diagnosticCodes: [ 2339 ]
}
I tested too many answers of sites, but one of them did not work. please help.

First, I think your declare file got some problems.
edit the file like
export {}
declare global {
namespace Express {
interface Request {
user: string;
}
}
}
or
namespace Express {
interface Request {
user?: string
}
}
add directory that contains the declare file in tsconfig. Since I usually name it express.d.ts and place in src/types folder, in my case, tsconfig.json will be edited like this
{
"compilerOptions": {
"typeRoots": ["src/types"],
}
}
lastly, also add ts-node configuration in tsconfig.json. (not in compilerOptions)
{
"ts-node": {
"files": true
}
}

Are you maybe looking for #types/express ?
You can also fix it with intersection type :
function endpoint (req: Request, res: Response & {user: string;}) {
console.log(req.user);
}
But maybe you are looking for req.body.user, type Response<{user: string;}> ?

Related

Vercel Serverless function results in "Cannot find module 'content-type'" when accessing req.body

I'm using NextJS with Vercel Serverless as described in this answer - https://stackoverflow.com/a/63659707/2826679 . My NodeJS function fails with an error message when I'm running it locally using vercel dev or when it's deployed to vercel servers.
My <PROJECT_ROOT>/api/report.ts looks like this and it fails at printing "3 req.body".
import type { VercelRequest, VercelResponse } from '#vercel/node';
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method === 'POST') {
console.log("1")
console.log("2", req)
console.log("3", req.body)
const data = {
test: "test"
};
return res.status(200).setHeader('content-type', 'application/json').end(JSON.stringify(data));
} else {
return res.status(404);
}
}
Error:
Unhandled rejection: Error: Cannot find module 'content-type'
Require stack:
- /Users/piotr/.config/yarn/global/node_modules/#vercel/node-bridge/helpers.js
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:1039:15)
at Function.Module._resolveFilename.sharedData.moduleResolveFilenameHook.installedValue [as _resolveFilename] (/Users/piotr/.config/yarn/global/node_modules/#cspotcode/source-map-support/source-map-support.js:811:30)
at Function.Module._load (node:internal/modules/cjs/loader:885:27)
at Module.require (node:internal/modules/cjs/loader:1105:19)
at require (node:internal/modules/cjs/helpers:103:18)
at Object.909 (/Users/piotr/.config/yarn/global/node_modules/#vercel/node-bridge/helpers.js:262:33)
at __webpack_require__ (/Users/piotr/.config/yarn/global/node_modules/#vercel/node-bridge/helpers.js:328:42)
at parseBody (/Users/piotr/.config/yarn/global/node_modules/#vercel/node-bridge/helpers.js:19:45)
at IncomingMessage.get [as body] (/Users/piotr/.config/yarn/global/node_modules/#vercel/node-bridge/helpers.js:212:27)
at handler (/Users/piotr/astrology/astroperspective/api/report.ts:7:26) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/Users/piotr/.config/yarn/global/node_modules/#vercel/node-bridge/helpers.js'
]
}
EDIT:
Now, I'm thinking that it has to do something with dependencies in package.json since my package.json is specifically for NextJS
Were you by any chance able to find out what was causing this? I'm running into the same error as well.

Express middleware undefined type

I am trying to create an authentication middleware for my express server and I get no Type errors in my IDE but when I try to complile I am getting TypeError: Cannot read properties of undefined (reading protect). The route works fine without the middleware and the middleware has no detectable linting issues. I am also using socket.io so I tried io.use(wrap(middleware)) on the off chance it would work and it didn't but that was a shot in the dark anyway, the problem seems unrelated. I've also tried replacing ALL relevant type declarations with any and got the same problem.
userController:
export const getMe = asyncHandler(async (req: IGetUserAuthInfoRequest, res: Response): Promise<void> => {
res.status(200).json(req.user)
})
RoutesController:
public static protect = asyncHandler(async (req: IGetUserAuthInfoRequest, res: Response, next: NextFunction): Promise<void> => {
let token: string
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
try {
token = req.headers.authorization.split(' ')[1]
const decoded: JwtPayload = jwt.verify(token, process.env.JWT_SECRET, { complete: true })
req.user = await UserModel.findById(decoded.id).select('-password')
next()
} catch (err) {
res.status(401)
throw new Error('Not authorised')
}
}
if (!token) {
res.status(401)
throw new Error('Not a valid token')
}
})
Extended express Request interface:
export interface IGetUserAuthInfoRequest extends Request {
user: any
}
userRouter:
userRouter.route('/me').get(RoutesController.protect, userController.getMe)
The error:
TypeError: Cannot read properties of undefined (reading 'protect')
at Object.<anonymous> (C:\Users\liams\dev\my-rest-server\src\routes\user.router.ts:8:46)
at Module._compile (node:internal/modules/cjs/loader:1097:14)
at Module._compile (C:\Users\liams\dev\my-rest-server\node_modules\source-map-support\source-map-support.js:568:25)
at Module.m._compile (C:\Users\liams\AppData\Local\Temp\ts-node-dev-hook-8639111545614118.js:69:33)
at Module._extensions..js (node:internal/modules/cjs/loader:1149:10)
at require.extensions.<computed> (C:\Users\liams\AppData\Local\Temp\ts-node-dev-hook-8639111545614118.js:71:20)
at Object.nodeDevHook [as .ts] (C:\Users\liams\dev\my-rest-server\node_modules\ts-node-dev\lib\hook.js:63:13)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Module.require (node:internal/modules/cjs/loader:999:19)
[ERROR] 20:08:00 TypeError: Cannot read properties of undefined (reading 'protect')
Any ideas what I'm missing?
EDIT: rather than posting everyline of my code here you can see it in the repo: https://github.com/dotDone/my-rest-server/tree/auth
Your RouteController is not defined yet when you use it in the user controller. ( Your architecture can be improved, but I will try to only answer your question, just know that there is a better way to organize all this )
Try the following
Turn UserRoutes to a class
import { Router } from 'express'
import * as userController from '../controllers/user.controller'
class UserRoutes {
constructor(routesController) {
this.userRouter: Router = Router();
this.routesController = routesController;
this.initRoutes();
}
initRoutes() {
userRouter.route('/').get(userController.getUsers).post(userController.createUser).put(userController.editUser).delete(userController.deleteUser)
userRouter.route('/me').get(this.routesController.protect, userController.getMe)
}
}
Then in your server.ts, create another function, call it initRoutes for example where you do something like this
constructor() {
this.startServer().then(() => this.startControllers()).then(() => this.initRoutes()).catch(err => console.log(err))
}
...
initRoutes() {
this.userRoutes = new UserRoutes(this.routesController);
}

Cannot find module imported in Nodejs Express

Hi everyone I'm learning about NodeJS and I'm having trouble importing between files
userController.js file
import userService from "../services/userService";
const userController = {
show: (request, response) => {
response.send(userService.show);
}
}
export default userController;
userService.js file
const userService = {
show: () => {
return 1;
}
}
export default userService;
I'm sure my path is correct
This is the error displayed in the console
internal/process/esm_loader.js:74
internalBinding('errors').triggerUncaughtException(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/path_here/services/userService' imported from /path_here/controllers/userController.js
at finalizeResolution (internal/modules/esm/resolve.js:285:11)
at moduleResolve (internal/modules/esm/resolve.js:708:10)
at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:819:11)
at Loader.resolve (internal/modules/esm/loader.js:89:40)
at Loader.getModuleJob (internal/modules/esm/loader.js:242:28)
at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:73:40)
at link (internal/modules/esm/module_job.js:72:36) {
code: 'ERR_MODULE_NOT_FOUND'
}
I tried to recall my knowledge but couldn't find the problem. Please help me check. Thanks
see do it like that
const file= required("./filename");

How to lint a typescript types file?

are there any ways to lint or otherwise debug a types file?
I have a index.d.ts file of all my types, but it seems to crash my app at startup.
using tsc with some basic options works fine
using tslint works fine.
but when running with the webpack compiler I get the following error.
the file contents are a lot but basically like the below.
I had some issues with exporting enums before but basically not getting any actual errors I can understand.
// we SEND to Boto
export enum MsgTypeOut {
TEXT = 0,
IMAGE = 1,
URL_LINK = 2,
FILE = 3,
}
export interface BotoTextMsg {
chatId: string
messageType: MsgTypeOut.TEXT
token?: string
payload: {
text: string
}
}
nodemon:watch early exit on watch, still watching (1) +14s
/Users/dc/dev/tix/recobot/stack/backend/server.js:2663
throw new Error("Module build failed: Error: Typescript emitted no output for /Users/dc/dev/tix/recobot/stack/shared/typezoo/index.d.ts.\n at successLoader (/Users/dc/dev/tix/recobot/stack/backend/node_modules/ts-loader/dist/index.js:47:15)\n at Object.loader (/Users/dc/dev/tix/recobot/stack/backend/node_modules/ts-loader/dist/index.js:29:12)");
^
Error: Module build failed: Error: Typescript emitted no output for /Users/dc/dev/tix/recobot/stack/shared/typezoo/index.d.ts.
at successLoader (/Users/dc/dev/tix/recobot/stack/backend/node_modules/ts-loader/dist/index.js:47:15)
at Object.loader (/Users/dc/dev/tix/recobot/stack/backend/node_modules/ts-loader/dist/index.js:29:12)
at Object.__awaiter (/Users/dc/dev/tix/recobot/stack/backend/server.js:2663:7)
at __webpack_require__ (/Users/dc/dev/tix/recobot/stack/backend/server.js:20:30)
at Object.defineProperty.value (/Users/dc/dev/tix/recobot/stack/backend/server.js:2551:19)
at __webpack_require__ (/Users/dc/dev/tix/recobot/stack/backend/server.js:20:30)
at Object.__awaiter (/Users/dc/dev/tix/recobot/stack/backend/server.js:867:16)
at __webpack_require__ (/Users/dc/dev/tix/recobot/stack/backend/server.js:20:30)
at Object.<anonymous> (/Users/dc/dev/tix/recobot/stack/backend/server.js:1306:18)
at Object.<anonymous> (/Users/dc/dev/tix/recobot/stack/backend/server.js:1343:30)
at __webpack_require__ (/Users/dc/dev/tix/recobot/stack/backend/server.js:20:30)
at Object.__awaiter (/Users/dc/dev/tix/recobot/stack/backend/server.js:1028:15)
at __webpack_require__ (/Users/dc/dev/tix/recobot/stack/backend/server.js:20:30)
at Object.defineProperty.value (/Users/dc/dev/tix/recobot/stack/backend/server.js:63:18)
at Object.<anonymous> (/Users/dc/dev/tix/recobot/stack/backend/server.js:66:10)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
[nodemon] app crashed - waiting for file changes before starting...
webpack config is pretty much vanilla based on create-react-app.
const fs = require("fs")
// const path = require("path")
const NodemonPlugin = require("nodemon-webpack-plugin");
const nodeModules = {};
fs.readdirSync("node_modules")
.filter(function (x) {
return [".bin"].indexOf(x) === -1;
})
.forEach(function (mod) {
nodeModules[mod] = "commonjs " + mod;
});
module.exports = {
entry: "./server/server.ts",
output: {
filename: "server.js",
// path: path.join(__dirname, "/build"),
},
externals: nodeModules,
// needed to fix https://github.com/webpack/webpack/issues/1599
node: {
__dirname: true
},
module: {
loaders: [
{
loader: "ts-loader",
test: /\.tsx?$/,
},
],
},
plugins: [new NodemonPlugin()],
resolve: {
extensions: [".webpack.js", ".web.js", ".ts", ".tsx", ".js"],
},
target: "node",
};
For anyone watching, the error is related to importing enums.
You can export an enum from a types.d.ts file... but it won't import and blows up in this weird way.
https://lukasbehal.com/2017-05-22-enums-in-declaration-files/
How to refer to Typescript enum in d.ts file, when using AMD?

InversifyJS - injectable is not a function

I'm trying to set up a NodeJS/TypeScript project using InversifyJS but I'm having some trouble getting off the ground. I've been looking at this for the past couple of days and can't figure out the issue. Everything builds correctly, but when I try to launch the Node server I get the following error:
TypeError: inversify_1.injectable is not a function
I'm running NodeJS v6.2.2 (Windows 10 x64) and have TypeScript 1.8 installed. I've tried building using both VS2015 and gulp. Below is a minimal example that I've tried that experiences the same error. I can't see anything wrong but I must be missing something obvious. (Sloppy code aside, it should still work.)
server.ts:
/// <reference path="./node_modules/reflect-metadata/reflect-metadata.d.ts" />
/// <reference path="./node_modules/inversify-dts/inversify/inversify.d.ts" />
/// <reference path="./typings/index.d.ts" />
import "reflect-metadata"
import { Application } from "./app/app"
import { ITest, TestClass } from "./app/testclass"
import { Kernel, injectable, inject } from "inversify"
var kernel = new Kernel();
kernel.bind<ITest>("ITest").to(TestClass);
kernel.bind<Application>(Application).to(Application);
var app = kernel.get<Application>(Application);
app.initialize();
app/app.ts
/// <reference path="../node_modules/inversify-dts/inversify/inversify.d.ts" />
/// <reference path="../typings/index.d.ts" />
import * as Hapi from "hapi";
import { inject, injectable } from "inversify"
import { ITest } from "../app/testclass"
#injectable()
export class Application {
private testClass: ITest;
constructor( #inject("ITest") test: ITest) {
this.testClass = test;
};
initialize() {
var server = new Hapi.Server({
connections: {
router: {
isCaseSensitive: false,
stripTrailingSlash: true
}
}
});
server.connection({
port: '3000',
host: 'localhost'
});
server.route({
method: 'GET',
path: '/',
handler: (request: Hapi.Request, reply: Hapi.IReply) => {
var str = this.testClass.test();
reply(str);
}
});
server.start(function () {
console.log('Server running at:', server.info.uri);
});
}
}
app/testclass.ts
/// <reference path="../node_modules/inversify-dts/inversify/inversify.d.ts" />
import { injectable } from "inversify"
export interface ITest {
test(): string;
}
#injectable()
export class TestClass implements ITest {
test(): string {
return "testing";
}
}
tsconfig.json
{
"files": [
"server.ts",
"app/app.ts",
"app/testclass.ts"
],
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"target": "es6",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"outDir": "../release/"
}
}
full error output from node:
C:\Projects\inversifytest\release\app\app.js:50
inversify_1.injectable(),
^
TypeError: inversify_1.injectable is not a function
at Object.<anonymous> (C:\Projects\inversifytest\release\app\app.js:50:17)
at Module._compile (module.js:541:32)
at Object.Module._extensions..js (module.js:550:10)
at Module.load (module.js:458:32)
at tryModuleLoad (module.js:417:12)
at Function.Module._load (module.js:409:3)
at Module.require (module.js:468:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (C:\Projects\inversifytest\release\server.js:6:15)
at Module._compile (module.js:541:32)
I figured it out - it was a dumb mistake as I suspected. I had the wrong version of InversifyJS installed. The decorators only work with the new version 2.x and npm had installed 1.3.1 (because I didn't explicitly specify a version).

Resources