This TypeScript error occurs when trying to augment modules using the older `import = require()` syntax. Module augmentation requires ES6-style `import` statements. The fix involves updating import syntax and ensuring proper module declaration merging.
The error "Cannot use module augmentation with import assignment" happens when you try to use TypeScript's module augmentation feature with the CommonJS-style import assignment syntax (`import x = require('module')`). Module augmentation allows you to add new declarations to existing modules, but it only works with ES6 module syntax (`import` and `export`). This is because module augmentation relies on TypeScript's declaration merging system, which requires proper module scope and ES6 module semantics. When you use `import = require()`, you're telling TypeScript to treat the module as a CommonJS module with a default export, which doesn't support the same declaration merging capabilities as ES6 modules. TypeScript needs the ES6 module structure to properly track and merge declarations across files.
Change from CommonJS import assignment to ES6 import syntax:
// ❌ Wrong - CommonJS import assignment
import express = require('express');
declare module 'express' {
interface Request {
user?: User;
}
}
// ✅ Correct - ES6 import syntax
import * as express from 'express';
declare module 'express' {
interface Request {
user?: User;
}
}Or if you need a default import:
// ✅ Also correct - ES6 default import
import express from 'express';
declare module 'express' {
interface Request {
user?: User;
}
}Ensure your TypeScript configuration uses ES6 modules or higher:
{
"compilerOptions": {
"module": "ESNext", // or "ES6", "ES2015", "ES2020", etc.
// other options...
}
}Avoid using "module": "CommonJS" if you need module augmentation. If you must output CommonJS for Node.js compatibility, you can still write ES6 modules and let TypeScript transpile them:
{
"compilerOptions": {
"module": "CommonJS", // Output format
"moduleResolution": "node",
"esModuleInterop": true, // Important for compatibility
"allowSyntheticDefaultImports": true
}
}With these settings, you can write ES6 imports and TypeScript will handle the conversion to CommonJS.
For cleaner code organization, create a separate .d.ts file for your module augmentations:
// types/express.d.ts
import * as express from 'express';
declare module 'express' {
interface Request {
user?: User;
timestamp?: number;
}
interface Response {
jsonSuccess(data: any): void;
}
}Then ensure this file is included in your TypeScript compilation. In tsconfig.json:
{
"compilerOptions": {
// ...
},
"include": [
"src/**/*",
"types/**/*.d.ts" // Include your declaration files
]
}This keeps your augmentations separate from implementation code and makes them easier to maintain.
Ensure the module you're augmenting actually has TypeScript declarations. Some modules might not have proper .d.ts files or might use different declaration styles.
Check if the module has its own types:
# Check if types are included
npm info @types/express # For DefinitelyTyped packages
npm info express types # For packages with built-in typesIf the module doesn't have TypeScript declarations, you might need to:
1. Install @types/module-name from DefinitelyTyped
2. Create your own ambient declarations
3. Use declare module without imports for ambient augmentation
For ambient augmentation (when you don't import the module):
// types/express.d.ts
declare module 'express' {
interface Request {
user?: User;
}
}
// No import needed - this is an ambient declarationCreate a simple test to verify your module augmentation works:
// test-augmentation.ts
import express from 'express';
const app = express();
// This should work if augmentation is correct
app.use((req, res, next) => {
req.user = { id: 1, name: 'Test' }; // Augmented property
req.timestamp = Date.now(); // Another augmented property
next();
});
// Also test augmented methods
app.get('/', (req, res) => {
res.jsonSuccess({ message: 'Hello' }); // Augmented method
});Compile and check for type errors:
npx tsc --noEmit test-augmentation.tsIf there are no errors, your module augmentation is working correctly.
## Understanding Module Augmentation vs Declaration Merging
Module augmentation is specifically for adding to *existing* module declarations. It differs from regular declaration merging in these ways:
1. Module augmentation uses declare module 'module-name' syntax and adds to modules from external packages or other files.
2. Declaration merging within the same file doesn't require declare module - TypeScript automatically merges interfaces, classes, etc.
## Common Pitfalls
1. Circular dependencies: If module A augments module B, and module B imports from module A, you might get confusing errors.
2. Global vs module augmentation: Use declare global for adding to global scope, declare module for specific modules.
3. Order matters: Augmentations must be in .d.ts files or files that don't produce runtime code. TypeScript processes them differently.
## Migration Strategy for Large Codebases
If you have a large codebase using import = require():
1. Start by converting only augmentation files to ES6 imports
2. Use esModuleInterop: true in tsconfig for compatibility
3. Gradually convert other files as needed
4. Consider using a codemod tool for bulk conversion
## TypeScript Version Considerations
- Older TypeScript versions (before 2.7) had more restrictions on module augmentation
- The esModuleInterop flag (introduced in TypeScript 2.7) helps bridge ES6 and CommonJS
- Always check the TypeScript version your project uses and consult the corresponding documentation
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