10

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"

7
  • Does this help you? stackoverflow.com/a/49130179/5493813 Commented Jan 19, 2022 at 7:59
  • @st.huber no, not really :/. I'm looking for a way to extend response.locals through an additional declaration file. Commented Jan 19, 2022 at 9:06
  • typeRoots option has a default value; make sure to include it Commented Jan 20, 2022 at 15:52
  • Have you tried including it in the files section of tsconfig? Commented Jan 25, 2022 at 10:36
  • @ShamPooSham Yes, I tried to include it there. Didn't change anything, unfortunetaly. Commented Jan 25, 2022 at 16:51

5 Answers 5

9

Looking at @types/express-serve-static-core/index.d.ts we can see that there is a global namespace Express with some interfaces that we can extend. One of them is Locals :)

The solution:

src/types.d.ts (or similar, include it in tsconfig, eg in the "types" field)

declare global {
  namespace Express {
    interface Locals {
      anything: 'here'
    }
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

What did it for me was declare module 'express-serve-static-core' instead of namespace Express
2

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.

2 Comments

userId is still assumed as any by TypeScript. Yes, it compiles. But I don't achieve type-safety this way.
I have edited my answer.
0

You can checkout my new lib express-typed which is small type safe typescript wrapper around express router.

With express-typed the returned types are inferred and exported from your backend, and later imported from your frontend.

Successfully deployed to production and improved development cycles!

Comments

0

This worked for me:

// ./types/express/index.d.ts
declare namespace Express {
  interface Locals {
    userId: number;
  }
}

add the ./types/express/index.d.ts inside "files" and "include" field in tsconfig.json

// tsconfig.json
{
  "compilerOptions": {
    ...
  },
  "include": ["./**/*.ts"],
  "files": ["./types/express/index.d.ts"]
}

*field "files" will not accept glob patterns, must add full path

Comments

0

The modern way to do this would be to use the second type parameter of the express Response object:

import express, { Response } from "express";

type UserLocals = {
  userId?: string;
}

const app = express();

app.use("/", (request, response: Response<any, UserLocals>, next) => {
    response.locals.userId = '123'; 
    next();
});

app.post("/", async (request, response: Response<any, UserLocals>) => {
    const { userId } = response.locals; // userId: string | undefined
});

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.