This TypeScript error occurs when you try to use 'declare module' statements in regular .ts files instead of .d.ts declaration files. Ambient module declarations can only exist in declaration files or within appropriate ambient contexts.
This error indicates that TypeScript encountered a `declare module` statement in a context where implementations are required. Ambient module declarations are type-only declarations that describe the shape of external modules. They exist purely for the type system at compile-time and don't generate any JavaScript code. According to TypeScript's rules, `declare module` statements can only appear in: 1. **Declaration files (.d.ts files)** - Files dedicated to type definitions 2. **Global scope of .d.ts files** - Top-level declarations 3. **Within `declare namespace` blocks** - Nested ambient contexts When you use `declare module` in a regular .ts file (which is a "non-ambient context" because it contains actual implementations), TypeScript throws this error because it doesn't know how to reconcile type-only module declarations with executable code.
First, locate the problematic declare module statement in your code:
// ❌ WRONG - in a regular .ts file
declare module 'some-external-module' {
export interface SomeInterface {
name: string;
}
export function doSomething(): void;
}
export function myFunction() {
// implementation
}The error occurs because you're mixing declare module (type-only) with executable code (export function) in the same file.
The primary solution is to move ambient module declarations to a dedicated declaration file with the .d.ts extension:
Create a new file: src/types/module-declarations.d.ts
// ✅ CORRECT - in a .d.ts file
declare module 'some-external-module' {
export interface SomeInterface {
name: string;
}
export function doSomething(): void;
}Declaration files (.d.ts) are treated as ambient contexts where declare module statements are allowed and expected. They contain only type information without implementations.
Keep your .ts files for implementation code and .d.ts files for module type declarations:
File structure:
src/
├── types/
│ └── module-declarations.d.ts # Module type definitions only
├── lib/
│ └── my-module.ts # Implementation code
└── index.tsExample separation:
module-declarations.d.ts:
declare module 'custom-module' {
export interface Config {
apiUrl: string;
timeout: number;
}
export function initialize(config: Config): void;
}my-module.ts:
import type { Config } from 'custom-module';
export function setupApp(config: Config) {
// implementation using the declared types
console.log('Connecting to ' + config.apiUrl);
}This clearly separates module type declarations from executable code.
If you're trying to augment an existing module's types, use the correct syntax:
// ✅ CORRECT - in a .d.ts file
declare module 'express' {
interface Request {
userId?: string;
userRole?: string;
}
}
// ✅ CORRECT - augmenting with new exports
declare module 'react' {
export interface Component {
customMethod?(): void;
}
}Module augmentation allows you to add types to existing modules without modifying their original declarations. This must be done in .d.ts files.
If you need to declare types for your own modules, create proper .d.ts files alongside your implementation:
For a module at `src/lib/my-utils.ts`:
// src/lib/my-utils.ts - Implementation
export function formatDate(date: Date): string {
return date.toISOString();
}
export function parseDate(str: string): Date {
return new Date(str);
}Create corresponding declaration:
// src/lib/my-utils.d.ts - Type declarations
export function formatDate(date: Date): string;
export function parseDate(str: string): Date;TypeScript will automatically use the .d.ts file for type checking while the .ts file provides the implementation.
Ensure your tsconfig.json is properly configured to include declaration files:
{
"compilerOptions": {
"declaration": true,
"declarationDir": "./dist/types",
"outDir": "./dist",
"rootDir": "./src",
"typeRoots": ["./node_modules/@types", "./src/types"],
"skipLibCheck": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}Key settings:
- typeRoots - Tells TypeScript where to find .d.ts files
- declaration: true - Generates .d.ts files from your TypeScript sources
- Include both .ts and .d.ts files in your includes/excludes
### Understanding Ambient Module Declarations
Ambient module declarations describe the shape of modules that exist outside your TypeScript project. They're used for:
- Describing third-party JavaScript libraries without TypeScript definitions
- Augmenting existing module types
- Declaring module patterns for non-standard imports
### Common Use Cases
Declaring CSS/SCSS modules:
// ✅ In a .d.ts file
declare module '*.css' {
const content: Record<string, string>;
export default content;
}
declare module '*.scss' {
const content: Record<string, string>;
export default content;
}Declaring image/assets modules:
// ✅ In a .d.ts file
declare module '*.png' {
const content: string;
export default content;
}
declare module '*.svg' {
const content: string;
export default content;
}Augmenting Node.js modules:
// ✅ In a .d.ts file
declare module 'fs' {
export function customMethod(path: string): boolean;
}### Module Declaration vs Module Implementation
Declaration (.d.ts):
declare module 'my-module' {
export function doSomething(): void;
export const version: string;
}Implementation (.ts):
// Actual module implementation
export function doSomething(): void {
console.log('Doing something');
}
export const version = '1.0.0';### Wildcard Module Declarations
For handling non-standard import patterns:
// ✅ In a .d.ts file
declare module '*/config.json' {
const value: { apiUrl: string; debug: boolean };
export default value;
}### TypeScript Version Compatibility
This error handling has been consistent across TypeScript versions. However, module declaration syntax has evolved:
- TypeScript 2.0+: Enhanced module resolution
- TypeScript 3.7+: Better wildcard module support
- TypeScript 4.0+: Improved module augmentation
Check your TypeScript version with:
tsc --version### Debugging Tips
1. Check file extensions: Ensure .d.ts for declarations, .ts for implementations
2. Verify tsconfig.json: Ensure proper include/exclude patterns
3. Use TypeScript compiler diagnostics: Run tsc --noEmit --diagnostics for detailed info
4. Check for conflicting declarations: Multiple .d.ts files declaring the same module can cause issues
### Migration Strategy
If you have existing .ts files with declare module statements:
1. Create corresponding .d.ts files
2. Move all declare module statements there
3. Update imports to reference the declared modules
4. Ensure implementations are in separate .ts files
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