This question has been asked several times, but none of the answers that were given have worked for me. I'm trying to extend the Express Request
object to include a property to store a User
object. I created a declaration file, express.d.ts
, and placed it in the same directory as my tsconfig.json
:
import { User } from "./src/models/user";
declare namespace Express {
export interface Request {
user: User;
}
}
Then I try to make an assignment to it in secured-api.ts
:
import express from 'express';
import { userService } from '../services/user';
router.use(async (req, res, next) => {
try {
const user = await userService.findByUsername(payload.username);
// do stuff to user...
req.user = user;
next();
} catch(err) {
// handle error
}
});
I get the following error:
src/routes/secured-api.ts:38:21 - error TS2339: Property 'user' does not exist on type 'Request'.
38 req.user = user;
~~~~
My User
class is:
import { Model, RelationMappings } from 'objection';
export class User extends Model {
public static tableName = 'User';
public static idColumn = 'username';
public static jsonSchema = {
type: 'object',
required: ['fname', 'lname', 'username', 'email', 'password'],
properties: {
fname: { type: 'string', minLength: 1, maxLength: 30 },
lname: { type: 'string', minLength: 1, maxLength: 30 },
username: { type: 'string', minLength: 1, maxLength: 20 },
email: { type: 'string', minLength: 1, maxLength: 320 },
password: { type: 'string', minLength: 1, maxLength: 128 },
}
};
public static modelPaths = [__dirname];
public static relationMappings: RelationMappings = {
};
public fname!: string;
public lname!: string;
public username!: string;
public email!: string;
public password!: string;
}
My tsconfig.json
is:
{
"compilerOptions": {
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"lib": ["es2015"], /* Specify library files to be included in the compilation. */
"outDir": "./build", /* Redirect output structure to the directory. */
"strict": true, /* Enable all strict type-checking options. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
}
}
My directory structure is:
backend/
package.json
tsconfig.json
express.d.ts
src/
models/
user.ts
routes/
secured-api.ts
What am I doing wrong here?
Express and Typescript packages are independent. The consequence of this is that Typescript does not “know” types of Express classes. There is a specific npm package for the Typescript to recognize the Express types.
JSON Request Body Express has a built-in express. json() function that returns an Express middleware function that parses JSON HTTP request bodies into JavaScript objects. The json() middleware adds a body property to the Express request req . To access the parsed request body, use req.
You generally use the req. body object to receive data through POST and PUT requests in the Express server. In your index.js file, set a POST request to the route '/login' : // POST https://example.com/login // // { // "email": "[email protected]", // "password": "helloworld" // } app.
The problem is that you are not augmenting the Express
global namespace defined by express
you are creating a new namespace in your module (the file becomes a module once you use an import
).
The solution is to declare the namespace in global
import { User } from "./src/models/user";
declare global {
namespace Express {
export interface Request {
user: User;
}
}
}
Or not use the module import syntax, just reference the type:
declare namespace Express {
export interface Request {
user: import("./src/models/user").User;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With