2

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

3 Answers 3

0

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.

Sign up to request clarification or add additional context in comments.

Comments

-1

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.

Comments

-1

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 enter image description here

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.