Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' - node.js

Please help, I am getting this error
src/app/middlewares/authentication.ts:16:17 - error TS2339: Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
16 req.user = user;
I have created the .d.ts file and also included it in tsconfig file. Still I am not able to run this code
Please find attached screenshots

Create a types folder in your src directory
Create a folder within the types folder with the name of the package you intend to extend. (In this case express).
Create an index.d.ts file in that folder
src/
- types/
- express/
- index.d.ts
add this code to the index file
import express from "express";
declare global {
namespace Express {
interface Request {
user?: Record<string,any>
}
}
}
remember to update your tsconfig.json file
{
"compilerOptions": {
"typeRoots" : ["./src/types", "./node_modules/#types"]
}
}
This should work

I was stuck on the same problem earlier. Here is how I solved it.
I created a separate directory called #types in my project for declaration merging to work.
Next I created a file in it called index.d.ts with following content. Please pay attention that we need to declare our own request within global. Also, importing express is important as well.
import * as express from "express"
declare global {
namespace Express {
interface Request {
user? : Record<string,any>
}
}
}
I added the following line under compilerOptions in my tsconfig.json.
"compilerOptions": {
...other settings,
"typeRoots": ["#types", "node_modules/#types"],
...other settings
}
And that's it. It should works with these changes.

Another way:
import { NextFunction, Request, Response } from 'express';
interface IDecode {
address: string,
role: string,
iat: number,
exp: number
};
interface RequestWithUserRole extends Request {
user?: IDecode,
}
const parseToken = (secret: string) =>
async (req: RequestWithUserRole, res: Response, next: NextFunction) => {
try{
const token = req.headers?.authorization?.split(' ')[1];
// console.log(req.headers?.authorization);
if (!token) {
return res.status(403).json({message: 'Token not found'})
}
const decodedData = <IDecode> jwt.verify(token, secret);
req.user = decodedData;
// console.log(decodedData);
return next();
}
catch(e) {
return res.status(500).json({e})
}
};

A quick walkaround if you are doing a quick prototype or following a tutorial
(req as any).user
NB: Do not use this in a real production app, because it would make your code dirty and it's not scalable.

Related

How to add custom properties on the Request object in Express + TypeScript?

I am trying to add a user object as a custom property in the Request object of Express, but I got the following error:
Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'
This is my code in a middleware function:
// Authenticate person/user through the database.
const person = new Person(username, password);
const user = await authenticate(person); // ORM => read DB
if (!user) {
return res
.status(401)
.json({ message: "Invalid Authentication Credentials" });
}
// attach user to request object
req.user = user; // <= HERE is my problem
next();
How I can add this custom property to the request?
I think the standard way to do this is by extending the Response interface exported by Express and declaring your Data as being part of the Locals generic type.
In #types/express/index.d.ts # line 127:
export interface Response<ResBody = any, Locals extends Record<string, any> = Record<string, any>>
extends core.Response<ResBody, Locals> {}
You can therefore create a Type that will be used in lieu of the default value for the Locals generic like so:
import type { Response, Request, NextFunction } from 'express';
import type { User } from './models'; // Or wherever it is, obviously.
type MyLocals = { user?: User; };
type MyResponse = Response<any, MyLocals>
// Using the `MyResponse` type is as simple as setting the type of `res` to be `MyResponse`, e.g.:
async function doSomeWork (req: Request, res: MyResponse, next: NextFunction): Promise<void> {
console.log(res.locals.user); // undefined | User
}
There are some other ways to achieve this, as well, but this is what I have always done when using Typescript + Express.

Typescript express typing on Request object

I seem to have an issue with Typescript typings on my Express Request object. The project for now exists out of 2 sub-projects (user-service and a common project which includes reusable Errors and Middlewares)
The common folder is installed as a dependency in the user-service like:
"#myPackage/common": "file:../common",
In there I have a current-user middleware:
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
interface UserPayload {
id: string;
email: string;
}
declare global {
namespace Express {
interface Request {
currentUser?: UserPayload;
}
}
}
const currentUser = (
req: Request,
res: Response,
next: NextFunction,
) => {
if (!req.session?.jwt) {
return next();
}
try {
const payload = jwt.verify(
req.session.jwt,
process.env.JWT_KEY!,
) as UserPayload;
req.currentUser = payload;
} catch (err) {
console.error(err);
}
return next();
};
export default currentUser;
with a declared global for the currentUser property on the Request object.
In my user-service project I have the following route
import express, { Request, Response } from 'express';
import { Middlewares } from '#myPackage/common';
const router = express.Router();
router.get('/api/users/currentuser', Middlewares.currentUser, (
req: Request,
res: Response,
) => {
res.send({ currentUser: req.currentUser || null });
});
export default router;
On req.currentUser I get the following error message:
Property 'currentUser' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
Shouldn't the package typings automatically be taken over in the code in which you import it? I hope I made myself clear on what the problem is :)
I've also always had trouble declaring a global namespace to attach types to express's request object. Found myself a solution using "declare module" instead of "declare global". So instead of
declare global {
namespace Express {
interface Request {
currentUser?: UserPayload;
}
}
}
maybe give the following approach a try:
declare module "express-serve-static-core" {
interface Request {
currentUser?: UserPayload;
}
}
Normally your currentUser property should also be available in other files with this approach, but you can of course export the manipulated Request interface if not.
Note that in most cases you will need to reference the "express-serve-static-core" module as this is where the Request interface is declared.

Accessing middleware injected data in Typescript

Here's a high level view of a controller in Typescript-Node :
As I'm storing details of user in product model, I have used a middleware to check if user if logged in before accessing the endpoint and also injecting user info to the req which can be further used in different controllers
exports.addProduct = async (req: Request, res: Response, next: NextFunction) => {
// images:
try {
// logic to handle data from req.body
// getting this user id from middleware isLoggedIn
// injecting user id into request in the isLoggedIn middleware
req.body.user = req.user._id;
const product = await Product.create(req.body);
return res.status(200).json({
success: true,
product,
});
} catch (error) {
logger.error(error);
}
};
Getting error : Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' , on the line
req.body.user = req.user._id;
isLoggedIn is typical function to check Bearer token or header or cookies and then inject user info to the request
It worked Perfectly in Javascript, now trying same in Typescript as a part to learn Typescipt
There are two ways to achieve this:
Extending express Request locally
Extending express Request globally
Using the local way require to write lots of redundent code and that's why
the global way is much better. it can be done by creating file as follows:
index.d.ts
import { User } from "../../models/user";
// to make the file a module and avoid the TypeScript error
export {};
declare global {
namespace Express {
export interface Request {
user: User;
}
}
}
Then add this config to tsconfig.json file
"typeRoots": [
"src/#types",
"./node_modules/#types",
],
Then Request object will recognize user and user can be injected from any middleware to be used in any controller.
The problem is that according to the typing of req, there is no property named user. TypeScript is notifying you that req.user should be undefined, according to the available typings. There are some possible solutions to fix your problem.
You could explicitly type the variable as any. This is considered to be bad practice sometimes, because in general you should try to type everything correctly (nevertheless: it works).
// Option 1: Explicitly declare variable as any
req.body.user = (req as any).user._id;
You could also check if req.user is defined, like this:
// Option 2: Check req.user manually
if (req.user) req.body.user = req.user._id;
else throw new Error("Some Error");
You could also type the req correctly, according to the API specifications of your middleware. This is usually a lot of work if done manually. Some modules ship with correct TypeScript-typings already.
Maybe you want to also look into this question since it is very similar to your question.
first create a folder call types it should be at the root of your project
then at yow tsconfig.json in the compilerOptions section add a paths prop
{
"compilerOptions": {
...
"paths": {
"express": [
"./types/express/index.d.ts"
],
}
}
then at the types dir add a new dir call express inside add an index.d.ts go ahead a copy them express definitions
// Type definitions for Express 4.17
// Project: http://expressjs.com
// Definitions by: Boris Yankov <https://github.com/borisyankov>
// China Medical University Hospital <https://github.com/CMUH>
// Puneet Arora <https://github.com/puneetar>
// Dylan Frankland <https://github.com/dfrankland>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
/* =================== USAGE ===================
import express = require("express");
var app = express();
=============================================== */
/// <reference types="express-serve-static-core" />
/// <reference types="serve-static" />
import * as bodyParser from 'body-parser';
import * as serveStatic from 'serve-static';
import * as core from 'express-serve-static-core';
import * as qs from 'qs';
/**
* Creates an Express application. The express() function is a top-level function exported by the express module.
*/
declare function e (): core.Express;
declare namespace e {
/**
* This is a built-in middleware function in Express. It parses incoming requests with JSON payloads and is based on body-parser.
* #since 4.16.0
*/
var json: typeof bodyParser.json;
/**
* This is a built-in middleware function in Express. It parses incoming requests with Buffer payloads and is based on body-parser.
* #since 4.17.0
*/
var raw: typeof bodyParser.raw;
/**
* This is a built-in middleware function in Express. It parses incoming requests with text payloads and is based on body-parser.
* #since 4.17.0
*/
var text: typeof bodyParser.text;
/**
* These are the exposed prototypes.
*/
var application: Application;
var request: Request;
var response: Response;
/**
* This is a built-in middleware function in Express. It serves static files and is based on serve-static.
*/
var static: serveStatic.RequestHandlerConstructor<Response>;
/**
* This is a built-in middleware function in Express. It parses incoming requests with urlencoded payloads and is based on body-parser.
* #since 4.16.0
*/
var urlencoded: typeof bodyParser.urlencoded;
/**
* This is a built-in middleware function in Express. It parses incoming request query parameters.
*/
export function query (options: qs.IParseOptions | typeof qs.parse): Handler;
export function Router (options?: RouterOptions): core.Router;
interface RouterOptions {
/**
* Enable case sensitivity.
*/
caseSensitive?: boolean | undefined;
/**
* Preserve the req.params values from the parent router.
* If the parent and the child have conflicting param names, the child’s value take precedence.
*
* #default false
* #since 4.5.0
*/
mergeParams?: boolean | undefined;
/**
* Enable strict routing.
*/
strict?: boolean | undefined;
}
interface SessionData {
userIp: string;
ipDetails: any;
publicKey: string;
session: string;
iv: string;
decrypted: any;
}
interface Application extends core.Application { }
interface CookieOptions extends core.CookieOptions { }
interface Errback extends core.Errback { }
interface ErrorRequestHandler<
P = core.ParamsDictionary,
ResBody = any,
ReqBody = any,
ReqQuery = core.Query,
Locals extends Record<string, any> = Record<string, any>
> extends core.ErrorRequestHandler<P, ResBody, ReqBody, ReqQuery, Locals> { }
interface Express extends core.Express { }
interface Handler extends core.Handler { }
interface IRoute extends core.IRoute { }
interface IRouter extends core.IRouter { }
interface IRouterHandler<T> extends core.IRouterHandler<T> { }
interface IRouterMatcher<T> extends core.IRouterMatcher<T> { }
interface MediaType extends core.MediaType { }
interface NextFunction extends core.NextFunction { }
interface Request<
P = core.ParamsDictionary,
ResBody = any,
ReqBody = any,
ReqQuery = core.Query,
Locals extends Record<string, any> = Record<string, any>
> extends core.Request<P, ResBody, ReqBody, ReqQuery, Locals> { }
interface RequestHandler<
P = core.ParamsDictionary,
ResBody = any,
ReqBody = any,
ReqQuery = core.Query,
Locals extends Record<string, SessionData> = Record<string, SessionData>
> extends core.RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals> { }
interface RequestParamHandler extends core.RequestParamHandler { }
export interface Response<ResBody = any, Locals extends Record<string, SessionData> = Record<string, SessionData>>
extends core.Response<ResBody, Locals> { }
interface Router extends core.Router { }
interface Send extends core.Send { }
}
export = e;
if you notice from the above I added an interface call SessionData if you look almost at the end I set Locals to be equals to it. at the Response
now at yow endPoint you can apply it like this
import type e from "express";
export const endPoint: e.RequestHandler = (req, res, next) => {
//code
};
you can go beong that you can also add them params if there are any, the res body, the req body and stuff
const endPoint: e.RequestHandler<YowParamsObj,YowResBodyObj,YowReqBodyObj,ThemQueryParamsObj> = (req, res, next) => {
//code
};

Express + TypeScript: Create type inference for response.locals

I want to add types for my response.locals. It is used to append data to your request-response cycle.
What I tried
// ./types/express/index.d.ts
declare global {
declare namespace Express {
interface Response {
locals: {
userId: number;
};
}
}
}
// tsconfig.json
"compilerOptions": {
"typeRoots": ["./types"],
}
myController.post("/", async (request, response) => {
// Can't get type in my controller
const { userId } = response.locals; // <- userId is any
Goal: Get correct type inference for my response.locals variable
Versions:
"express": "^4.17.1",
"#types/express": "^4.17.8",
"typescript": "^4.5.4"
Without a proper TypeScript background, I was able to compile the following (after some trial and error):
import {Request, Response} from "express";
interface Locals extends Record<string, any> {
userId: number;
}
interface MyResponse extends Response {
locals: Locals;
}
export function middleware(request: Request, response: MyResponse) {
const {userId} = response.locals;
response.end(userId);
return userId;
}
The declaration file (.d.ts) contains:
export declare function middleware(request: Request, response: MyResponse): number;
so the number type was correctly inferred.
And it works when I use this middleware function in express.

TypeError when trying to create GraphQL Directive

I'm using Apollo-Server/TypeScript and utilizing graphql-tool's makeExecutableSchema() to setup schema/directives.
I'm currently getting this error when trying to add a barebones simple GraphQL Directive:
TypeError: Class constructor SchemaDirectiveVisitor cannot be invoked without 'new' at new AuthDirective
(/home/node/app/src/api/directives/AuthDirective.ts:58:42)
Here is the setup for the schema:
import AuthDirective, { authTypeDefs } from "./directives/AuthDirective";
import { makeExecutableSchema } from "graphql-tools";
const schema = makeExecutableSchema({
resolvers: [...],
typeDefs: [...], // authTypeDefs is included here
schemaDirectives: {
auth: AuthDirective,
},
});
export default schema;
The AuthDirective file:
import { SchemaDirectiveVisitor } from "graphql-tools";
import { defaultFieldResolver } from "graphql";
export default class AuthDirective extends SchemaDirectiveVisitor {
public visitFieldDefinition(field) {
console.log("VISIT FIELD: ", field);
const { resolve = defaultFieldResolver } = field;
field.resolve = async function (...args) {
return resolve.apply(this, args);
};
}
}
export const authTypeDefs = `
enum AppRole {
USER
ADMIN
}
directive #auth(
requires: AppRole! = USER
) on FIELD_DEFINITION
`;
I've been following the documentation here. Everything seems to be in order but I could be overlooking something.
What's absurd though is that the error is saying something about line 58 in the AuthDirective file.
The file is only 23/24 lines long.
Fixed the issue. I've changed the way of implementing directives using graphql-tools directive resolvers (instead of the class-based SchemaDirectiveVisitor way). Documentation here

Resources