Report #65625
[bug\_fix] Property 'user' does not exist on type 'Request'.
Use TypeScript's module augmentation \(declaration merging\) by creating a type declaration file \(e.g., \`src/types/express.d.ts\`\) that contains \`import 'express';\` followed by \`declare module 'express' \{ interface Request \{ user?: \{ id: string; email: string \} \} \} \}\`, and ensure this file is included in the \`tsconfig.json\` "include" array. The root cause is that the Express Request interface is defined in the \`@types/express\` package and is sealed; to add custom properties \(like those added by authentication middleware\), you must use declaration merging to augment the existing interface without modifying the original package files.
Journey Context:
Developer is building an Express.js API with TypeScript. They create an authentication middleware that decodes a JWT and attaches the user payload to the request object: \`req.user = decoded;\`. In a subsequent route handler, they attempt to access \`req.user.id\` and TypeScript immediately flags the error: "Property 'user' does not exist on type 'Request'". The developer first tries to fix it by casting: \`\(req as any\).user\`, which works but loses all type safety and propagates \`any\` through the codebase. They search "typescript express extend request" and find references to "declaration merging" and "module augmentation". They create a file \`src/types/express/index.d.ts\` and write:
\`\`\`
declare module 'express' \{
interface Request \{
user?: \{ id: string; \}
\}
\}
\`\`\`
They reload VSCode, but the error persists. They realize that for module augmentation to work, the file must be a module \(contain at least one top-level import or export statement\) rather than a script. They add \`import \* as express from 'express';\` at the top of the file. Now it works in the IDE. However, when they run \`tsc --noEmit\`, they get errors about the file not being included. They check \`tsconfig.json\` and see \`"include": \["src/\*\*/\*"\]\`, which should cover \`src/types/express/index.d.ts\`. After some debugging, they realize the file was being excluded by a separate \`exclude\` pattern or the \`types\` compiler option was overriding it. They explicitly add \`"src/types/\*\*/\*"\` to the include array. The error disappears and \`req.user\` is now fully typed throughout the application. The fix works because TypeScript's declaration merging allows ambient modules to contribute to existing interface declarations, but only when the augmentation file is treated as a module \(via import/export\) and is included in the compilation context.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T16:38:13.086445+00:00— report_created — created