J'essaie d'ajouter une propriété pour exprimer un objet de requête à partir d'un middleware à l'aide de TypeScript. Cependant, je ne sais pas comment ajouter des propriétés supplémentaires à l’objet. Je préférerais ne pas utiliser la notation entre crochets, si possible.
Je cherche une solution qui me permettrait d’écrire quelque chose de similaire à ceci (si possible):
app.use((req, res, next) => {
req.property = setProperty();
next();
});
Vous souhaitez créer une définition personnalisée et utiliser une fonctionnalité dans TypeScript appelée Fusion de déclarations . Ceci est couramment utilisé, par exemple. dans method-override
.
Créer un fichier custom.d.ts
et assurez-vous de l'inclure dans votre tsconfig.json
_ section files
- le cas échéant. Le contenu peut ressembler à ceci:
declare namespace Express {
export interface Request {
tenant?: string
}
}
Cela vous permettra, à tout moment dans votre code, d'utiliser quelque chose comme ceci:
router.use((req, res, next) => {
req.tenant = 'tenant-X'
next()
})
router.get('/whichTenant', (req, res) => {
res.status(200).send('This is your tenant: '+req.tenant)
})
Comme suggéré par le commentaires dans le index.d.ts
, vous déclarez simplement à l’espace de nom global Express
tout nouveau membre. Exemple:
declare global {
namespace Express {
interface Request {
context: Context
}
}
}
import * as express from 'express';
export class Context {
constructor(public someContextVariable) {
}
log(message: string) {
console.log(this.someContextVariable, { message });
}
}
declare global {
namespace Express {
interface Request {
context: Context
}
}
}
const app = express();
app.use((req, res, next) => {
req.context = new Context(req.url);
next();
});
app.use((req, res, next) => {
req.context.log('about to return')
res.send('hello world world');
});
app.listen(3000, () => console.log('Example app listening on port 3000!'))
L'extension des espaces de noms globaux est couverte plus sur mon GitBook .
La réponse acceptée (comme les autres) ne fonctionne pas pour moi mais
declare module 'express' {
interface Request {
myProperty: string;
}
}
fait. J'espère que cela aidera quelqu'un.
Aucune des solutions proposées n'a fonctionné pour moi. J'ai fini par simplement étendre l'interface de requête:
import {Request} from 'express';
export interface RequestCustom extends Request
{
property: string;
}
Puis l'utiliser:
import {NextFunction, Response} from 'express';
import {RequestCustom} from 'RequestCustom';
someMiddleware(req: RequestCustom, res: Response, next: NextFunction): void
{
req.property = '';
}
Edit: Des versions récentes de TypeScript s'en plaignent. Au lieu de cela, je devais faire:
someMiddleware(expressRequest: Request, res: Response, next: NextFunction): void
{
const req = expressRequest as RequestCustom;
req.property = '';
}
Pour les nouvelles versions d’express, vous devez augmenter le express-serve-static-core
module.
Cela est nécessaire car l'objet Express provient désormais de là: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/8fb0e959c2c7529b5fa4793a44b41b797ae671b9/types/express/index.d.ts#L19
Fondamentalement, utilisez ce qui suit:
declare module 'express-serve-static-core' {
interface Request {
myField?: string
}
interface Response {
myField?: string
}
}
Dans TypeScript, les interfaces sont ouvertes. Cela signifie que vous pouvez leur ajouter des propriétés où que vous soyez en les redéfinissant.
Étant donné que vous utilisez ce fichier express.d.ts , vous devriez pouvoir redéfinir l'interface Request pour ajouter le fichier champ supplémentaire.
interface Request {
property: string;
}
Ensuite, dans votre fonction middleware, le paramètre req devrait également avoir cette propriété. Vous devriez pouvoir l'utiliser sans aucune modification de votre code.
Une solution possible consiste à utiliser "double casting à tout"
1- définir une interface avec votre propriété
export interface MyRequest extends http.IncomingMessage {
myProperty: string
}
2- double casting
app.use((req: http.IncomingMessage, res: http.ServerResponse, next: (err?: Error) => void) => {
const myReq: MyRequest = req as any as MyRequest
myReq.myProperty = setProperty()
next()
})
Les avantages de la double coulée sont les suivants:
-noImplicitany
drapeauAlternativement, il y a l'itinéraire rapide (non typé):
req['myProperty'] = setProperty()
(ne modifiez pas les fichiers de définition existants avec vos propres propriétés - cela n'est pas maintenable. Si les définitions sont fausses, ouvrez une demande d'extraction)
EDIT
Voir le commentaire ci-dessous, le casting simple fonctionne dans ce cas req as MyRequest
Bien que ce soit une très vieille question, je suis tombé sur ce problème récemment. La réponse acceptée fonctionne bien, mais je devais ajouter une interface personnalisée à Request
- une interface que j'utilisais dans mon code et qui ne fonctionnait pas. si bien travailler avec la réponse acceptée. Logiquement, j'ai essayé ceci:
import ITenant from "../interfaces/ITenant";
declare namespace Express {
export interface Request {
tenant?: ITenant;
}
}
Mais cela n’a pas fonctionné car TypeScript traite .d.ts
Les fichiers en tant qu'importations globales et lorsqu'ils sont importés, ils sont traités comme des modules normaux. C'est pourquoi le code ci-dessus ne fonctionne pas avec un paramètre TypeScript standard.
Voici ce que j'ai fini par faire
// typings/common.d.ts
declare namespace Express {
export interface Request {
tenant?: import("../interfaces/ITenant").default;
}
}
// interfaces/ITenant.ts
export interface ITenant {
...
}