19

I'm using Express and I'm trying to explicitly define res.locals. In the @types/express package, Express.Response.locals is any, so I can't seem to overwrite it:

types/express/index.d.ts:

declare namespace Express {
  interface Response {
    locals: {
      myVar: number
    }
  }
}

My Middleware:

import * as express from 'express'

function middleware(
  req: express.Request, 
  res: express.Response, 
  next: express.nextFunction
) {
  res.locals.myVar = '10' // I want this to throw a compiler error
  next()
}

I want my wrong assignment of res.locals.myVar to error, but res.locals is still any according to my autocompletion.

How can I remove any and completely replace it?

3 Answers 3

21

I recently ran into this issue and managed to resolve it by creating an index.d.ts in my src folder to overwrite res.locals, my implementation looked like this:

// src/index.d.ts
import 'express';

interface Locals {
  message?: string;
}

declare module 'express' {
  export interface Response  {
    locals: Locals;
  }
}

Make sure you also have it included in your tsconfig.json, e.g

// somewhere in your tsconfig.json
  "include": [
    "src/**/*.ts"
  ]

You would use the interface just as you would normally

import { Request, Response, NextFunction } from 'express';

export const handler = (req: Request, res: Response, next: NextFunction) => {
  // should be typed
  res.locals.message = 'hello'
}

Hope this helps!

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

8 Comments

Hey @natterstefan, make sure you import express at the top of the index.d.ts
Thank you @Faris, worked for me now. Do you also know how to extend Express.Handler so I do not need to add res: Response, but still be able to use the custom Response interface?. Edit: Maybe you can link to this resource as well in your answer -> github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/…
I think this answer is now obsolete. Here's what worked for me (express 4.16.1): stackoverflow.com/a/55718334/3670829
Also didn't work for me in express 4.17
|
7

The current accepted answer is outdated and broken. The new solution is to add the following to a *.d.ts file in the project like below:

{
    "compilerOptions": {
        // All your typescript compiler options
    },
    "include": ["src/**/*", "types/*.ts"],
}

Then create a locals.d.ts inside your types folder and add all your custom properties. Be sure to provide the correct path of the types folder. In my include option, my types are in the root directory of the project.

declare global {
  namespace Express {
    interface Locals {
      shopify: { session: Session }
    }
  }
}

Explanation can be found here.

4 Comments

this works really nicely
@elnygren This still lets you put anything on the interface w/o it caring. Do you know how to make it so locals is only what you specify? In this example only shopify we be on the locals and if you tried to write something else it would error out.
@topched Just make an interface and export it. Then import it anywhere where you want to use it locally. There are many other solutions too. This is the simplest.
declare the interface for Locals worked!
2

Unfortunately there is no way to override any using interface merging. You can so some surgery on the type and replace the type using mapped and conditional types:

import * as express from 'express'

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

type MyResponse = Omit<express.Response, "locals"> & { 
  locals: {
    myVar: number
  }
}
function middleware(
  req: express.Request, 
  res: MyResponse, 
  next: express.NextFunction
) {
  res.locals.myVar = '10' // error now
  next()
}

1 Comment

This throws Type '(request: Request<ParamsDictionary, any, any, ParsedQs>, response: MyResponse) => Promise<Response<any> | undefined>' is missing the following properties from type 'Application': init, defaultConfiguration, engine, set, and 61 more. for me. I'm using express 4.17.

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.