TypeScript emits this error when a module or global augmentation tries to redeclare a symbol that already exists with a conflicting shape, typically while extending third-party type definitions or maintaining multiple .d.ts files.
TypeScript transparently merges declarations with the same name, so augmentations are only safe when every file agrees on how a type looks. When the compiler sees two augmentations of the same symbol that disagree on optional/required members or types it already knows about, it raises "Type augmentation conflicts with existing declaration" and refuses to merge them. This usually happens in extension files that sit next to existing definitions from @types packages or that accidentally run in the global scope instead of the module scope required for deliberate merging. Keeping augmentations tightly aligned with the shipped declarations prevents the conflict and keeps the compiler happy.
Start the file with an import so the compiler treats it as a module-level augmentation rather than a global script. This scope guarantees TypeScript merges your additions with the shipped declaration instead of generating a conflicting second declaration.
import "express"; // keeps this file as an external module
declare module "express-serve-static-core" {
interface Request {
requestId?: string;
}
}If you omit the import, TypeScript will combine your file with the global scope and may see two declarations for the same interface, which triggers the conflict.
Open the package's .d.ts file inside node_modules/@types (or the package itself) before adding properties. Match the casing and optionality of existing members to avoid duplicate declarations with different names.
Use resolution tracing to confirm which file TypeScript loads for the module:
npx tsc --traceResolution | grep "express.d.ts"If the trace shows a different file than the one you edited, you are augmenting the wrong declaration and the compiler treats your work as a conflicting declaration on top of the shipped definition. Move your augmentation next to the file that actually defines the module or reference it directly via the /// <reference path="..."> directive when necessary.
When you need to change a property from the shipped declaration, declare only the new optional members or use helper types instead of repeating the property with a different type.
type Overwrite<T, K extends keyof T, V> = Omit<T, K> & V;
declare module "express-serve-static-core" {
interface Request extends Overwrite<Request, "user", { user: CustomUser }> {}
}The compiler now merges your augmentation by replacing specific keys via Overwrite, so it never emits the conflicting property twice. If you must adjust an exported member's type, define a new property (e.g., customUser) and leave the original untouched, or introduce a new interface that extends the existing one instead of re-declaring it.
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript