This TypeScript error occurs when you attempt to use global augmentation (declare global) in a file that TypeScript doesn't recognize as an external module. Global augmentation requires the file to be treated as a module, which happens when it contains import or export statements.
In TypeScript, global augmentation allows you to extend global type definitions (like Window, Document, or Node.js globals) using the declare global syntax. However, TypeScript enforces a strict rule: a file must be recognized as an external module (by containing import/export statements) for global augmentation to work within it. The error "Global augmentation is not allowed outside of external module" means you're trying to augment global types in a context where TypeScript doesn't recognize your current file as a proper module. This typically happens when: 1. Your .d.ts file is treated as a script (global scope) rather than a module 2. Your file lacks the necessary import/export statements to be recognized as a module 3. You're trying to use declare global in a file that TypeScript considers a "script file" Without an explicit module context, TypeScript treats declarations as global by default, which conflicts with the intent of declare global statements that should only be used within module contexts to extend global types.
The simplest fix is to add an empty export statement at the end of your file. This ensures TypeScript treats your file as a module rather than a global script:
// ❌ Wrong - no exports, treated as global script
declare global {
interface Window {
customProperty: string;
}
}
// ✅ Correct - export makes it a module
declare global {
interface Window {
customProperty: string;
}
}
export {}; // Makes this file a moduleThe export {} statement tells TypeScript "treat this as a module" without actually exporting anything. It's a common pattern in .d.ts files where you only want to augment global types.
If you prefer not to use export {}, you can add an import statement at the beginning of your file:
// ✅ Correct - import makes it a module
import 'some-module'; // Import anything, even if unused
declare global {
interface Document {
customMethod(): void;
}
}The import statement doesn't need to import anything specific—it just signals to TypeScript that this is a module file, enabling global augmentation syntax. You can import a module you're already using or create a dummy import.
Create a dedicated .d.ts file for your global augmentations with proper module context:
// ✅ Good structure for types/global-augmentation.d.ts
declare global {
interface Window {
myCustomAPI: {
doSomething(): void;
};
}
interface Navigator {
userAgentData?: {
brands: Array<{ brand: string; version: string }>;
mobile: boolean;
platform: string;
};
}
}
export {}; // Required for module contextInclude it in tsconfig.json:
{
"include": [
"src/**/*",
"types/**/*.d.ts"
]
}This ensures the file is recognized as a module and properly processed by TypeScript.
Verify your file has module context by checking for import/export statements:
// ❌ Script context (no imports/exports) - declare global won't work
// types/custom.d.ts
declare global {
interface Process {
customEnv: Record<string, string>;
}
}
// ✅ Module context (has export) - declare global works
// types/custom.d.ts
declare global {
interface Process {
customEnv: Record<string, string>;
}
}
export {}; // This makes it a module!Files without top-level import or export statements are treated as scripts, where all declarations are automatically global. In script context, you don't need declare global—just declare interfaces directly.
If you're creating new global types (not augmenting existing ones), you don't need declare global:
// ✅ Creating new global types in script context
// types/globals.d.ts (no imports/exports = script file)
interface MyGlobalType {
id: string;
name: string;
}
// This works because file is a script, declarations are global
// No declare global neededOnly use declare global when you need to extend existing global interfaces (Window, Document, etc.) within a module context.
Ensure your augmentation files are included in your tsconfig.json:
{
"compilerOptions": {
"declaration": true,
"declarationDir": "./types"
},
"include": [
"src/**/*",
"types/**/*.d.ts", // Include your .d.ts files
"global.d.ts" // Include root-level .d.ts files
]
}If your augmentation file is in a subdirectory, make sure it's explicitly included in the "include" array. TypeScript must be able to find and process the file.
Place global augmentations in .d.ts files with clear naming:
# Good structure
types/
├── global-augmentations.d.ts # Global type extensions
├── module-augmentations.d.ts # Module-specific extensions
└── custom-types.d.ts # Custom type definitions
# In tsconfig.json
{
"include": ["src/**/*", "types/**/*.d.ts"]
}Avoid mixing global augmentations with regular code in .ts files. Keep them separate in .d.ts files for clarity and proper TypeScript processing.
TypeScript has two file modes: script mode and module mode. A file is in module mode if it contains at least one top-level import or export statement. Files without imports/exports are in script mode, where all declarations are automatically global.
The declare global syntax is specifically designed for module files that want to contribute to the global namespace. This is counter-intuitive but important: you can only augment global types from within a module context.
Key distinctions:
- Script files: No imports/exports, declarations are automatically global
- Module files: Has imports/exports, needs declare global to add to global namespace
- declare global: Only works in module files, extends existing global interfaces
When TypeScript processes .d.ts files, it follows the same rules. A .d.ts file without imports/exports is a script, so its declarations are global. To use declare global in a .d.ts file, you must add export {} to make it a module.
This design prevents accidental global pollution from module files while allowing intentional global augmentation when needed.
In monorepo setups or complex project structures, ensure your global augmentation files are included in the appropriate tsconfig.json. The file must be processed as a module (have import/export) to use declare global.
For libraries publishing type definitions, consider whether global augmentation is appropriate. Often, module augmentation (declare module) is preferred over global augmentation to avoid polluting the global namespace for users who don't need the extensions.
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