This error occurs when you try to augment (extend) a module using TypeScript's declaration merging, but the original module doesn't export the type or interface you're trying to augment. The fix involves ensuring the module exports the expected types or correcting your augmentation syntax.
TypeScript's module augmentation feature allows you to extend existing module declarations without modifying the original files. When you use `declare module 'module-name'`, you're telling TypeScript to merge your new declarations with the original module's exports. This error appears when: 1. The original module doesn't actually export what you're trying to augment 2. You're augmenting a module that doesn't exist or isn't installed 3. There's a mismatch between how you declared the export and how the original module exports it 4. You're using re-exported modules (indirect exports from index files) Module augmentation is particularly useful for adding types to third-party libraries, extending global objects, or merging namespaces. However, TypeScript strictly enforces that you can only augment exports that actually exist in the original module.
First, confirm that the original module actually exports the type or interface you want to augment. Check the library's type definition file or source code.
For example, if you're trying to augment a type called Response:
// WRONG - if Response is not exported
declare module 'my-lib' {
interface Response {
customField: string;
}
}Check the library's index.d.ts or package.json types field to see what's actually exported:
cat node_modules/my-lib/index.d.ts | grep -i "export.*Response"Or look in the actual source:
cat node_modules/my-lib/package.json | grep -E '"types"|"typings"'Sometimes the export is named differently than expected. For example, the library might export HttpResponse but you're trying to augment Response.
// WRONG - augmenting the wrong name
declare module 'http-lib' {
interface Response {
custom: string;
}
}
// CORRECT - use the actual export name
declare module 'http-lib' {
interface HttpResponse {
custom: string;
}
}Check what names are actually exported:
grep "^export" node_modules/your-lib/index.d.tsModule augmentation requires the exact module path. For scoped packages or submodules, use the full path:
// For @scope/package
declare module '@scope/package' {
interface Response {
custom: string;
}
}
// For submodules
declare module '@scope/package/utils' {
interface Response {
custom: string;
}
}
// NOT just 'package' - that won't find the module
declare module 'package' {
interface Response {
custom: string;
}
}To find the exact path, check how the module is imported in your code:
import { Response } from '@scope/package/api'; // Use '@scope/package/api' for augmentation
import { Response } from 'my-lib'; // Use 'my-lib' for augmentationIf a module re-exports types using export * from, TypeScript may not allow augmentation on the re-exporting module. You need to augment the original source module instead.
For example, if node_modules/my-lib/index.ts contains:
export * from './types/response';Then augment the original source path:
// WRONG - augmenting the re-export
declare module 'my-lib' {
interface Response {
custom: string;
}
}
// CORRECT - augment the original source
declare module 'my-lib/types/response' {
interface Response {
custom: string;
}
}Check the module structure:
cat node_modules/my-lib/index.d.tsIf you're defining your own types to augment, use inline export keywords instead of separate export statements:
// WRONG - export clause can cause issues
interface MyType {
value: string;
}
export { MyType };
// CORRECT - inline export
export interface MyType {
value: string;
}This prevents duplicate identifier conflicts during module augmentation.
Module augmentation only works with direct exports, not re-exports. If the original module only re-exports from another package:
// In original-lib/index.ts
export type Response = require('other-lib').Response; // This is a re-export
// TypeScript may reject augmentation because Response is not directly exported
declare module 'original-lib' {
interface Response {
custom: string;
}
}In this case, you may need to augment the source library instead or use a different approach.
### Module Augmentation Best Practices
Use separate .d.ts files for augmentations: Keep augmentations in their own declaration files for clarity:
// types/augmentations.d.ts
declare module 'express' {
interface Request {
userId?: string;
}
}Import the augmented module first: Always import the original module before declaring augmentations, or the augmentation won't work:
import 'my-lib'; // Import first
declare module 'my-lib' {
interface Config {
custom: string;
}
}Troubleshooting with TypeScript Compiler:
If you're still unsure what's exported, use the TypeScript compiler in declaration mode:
npx tsc --declaration --emitDeclarationOnly --noEmitTypeScript Version Compatibility: Module augmentation behavior varies slightly between TypeScript versions. If updating TypeScript fixes the issue, that's a clue that your augmentation syntax relies on newer features.
Alternative: Use Namespaces: For some use cases, extending a namespace is safer than module augmentation:
// If the module exports a namespace
declare namespace MyLib {
interface Config {
custom: string;
}
}Check tsconfig.json: Ensure your tsconfig includes the types directory and has the right module resolution:
{
"compilerOptions": {
"moduleResolution": "node",
"typeRoots": ["./node_modules/@types", "./types"],
"skipLibCheck": false
}
}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