This TypeScript compilation error occurs when trying to use a namespace without proper import syntax. Namespaces in TypeScript require explicit import statements using 'import as' syntax or namespace qualifiers to access their contents.
This error occurs when you attempt to use a TypeScript namespace without properly importing or referencing it. TypeScript namespaces are a way to organize code and prevent naming collisions, but they require specific syntax to access their contents. When you define a namespace like `namespace MyNamespace { export const value = 1; }`, you cannot directly reference `value` without either: 1. Importing the namespace with `import as` syntax 2. Using the namespace qualifier `MyNamespace.value` The error message "Namespace must be imported or aliased using 'import as'" is TypeScript's way of telling you that you're trying to use something from a namespace without following the proper access rules. This is different from ES6 modules, which use different import/export syntax.
When importing from a namespace, use the import as syntax:
// Incorrect - will cause error
import { SomeFunction } from './my-namespace';
// Correct - use 'import as' for namespaces
import * as MyNamespace from './my-namespace';
// Then access with MyNamespace.SomeFunction
// Alternative: import specific members with alias
import { SomeFunction as MyFunction } from './my-namespace';This tells TypeScript you're importing a namespace module rather than an ES6 module.
If you're referencing members within the same file but different namespace, use the namespace qualifier:
namespace MyNamespace {
export const value = 42;
}
// Incorrect - direct reference
const x = value; // Error!
// Correct - use namespace qualifier
const x = MyNamespace.value;
// Also correct - import with 'import as' even in same file
import MyAlias = MyNamespace;
const y = MyAlias.value;This applies even when the namespace is in the same file.
Ensure your TypeScript configuration supports namespace syntax:
{
"compilerOptions": {
"module": "commonjs", // or "amd", "system", "umd"
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
}
}Namespaces work best with CommonJS or AMD module systems. If using ES6 modules ("module": "es2015" or higher), consider converting namespaces to ES6 modules.
Modern TypeScript projects should prefer ES6 modules over namespaces. Convert:
// Old namespace style
namespace Utilities {
export function helper() { /* ... */ }
}
// New ES6 module style
// utilities.ts
export function helper() { /* ... */ }
// consumer.ts
import { helper } from './utilities';ES6 modules are standardized, tree-shakeable, and work better with modern bundlers like Webpack and Rollup.
For global namespace declarations (like in .d.ts files), use triple-slash references:
/// <reference path="./my-globals.d.ts" />
// Now you can use the namespace
const x = MyGlobalNamespace.someValue;Or declare them globally:
// my-globals.d.ts
declare namespace MyGlobalNamespace {
export const someValue: string;
}This makes the namespace available throughout your project without imports.
Ensure TypeScript can find your namespace files:
// Check file extensions
import * as MyNamespace from './my-namespace.ts'; // .ts extension
import * as MyNamespace from './my-namespace.js'; // .js extension in output
// Use path mapping in tsconfig.json for complex structures
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@namespaces/*": ["src/namespaces/*"]
}
}
}
// Then import
import * as MyNamespace from '@namespaces/my-namespace';Proper module resolution ensures TypeScript can locate and understand namespace declarations.
### Namespace vs Module History
TypeScript namespaces (originally called "internal modules") were created before ES6 modules were standardized. They provide a way to organize code and avoid global scope pollution. With the adoption of ES6 modules, namespaces are now primarily used for:
1. Declaration files (.d.ts): Organizing type definitions for libraries
2. Legacy codebases: Projects that predate ES6 module support
3. Global augmentations: Adding to existing global interfaces
### Module Resolution Strategies
TypeScript uses different resolution strategies:
- Classic: Looks for .ts/.d.ts files (used with AMD/System modules)
- Node: Mimics Node.js require() resolution (default for CommonJS)
- Bundler: For Webpack/Rollup (TypeScript 4.7+)
Namespaces work with all strategies but may require explicit configuration.
### Namespace Merging
TypeScript supports namespace merging, where multiple declarations contribute to the same namespace:
// file1.ts
namespace MyLib {
export function func1() { /* ... */ }
}
// file2.ts
namespace MyLib {
export function func2() { /* ... */ }
}
// Both functions are available in MyLibThis is useful for splitting large namespaces across files.
### Compatibility with Bundlers
Modern bundlers (Webpack, Rollup, Vite) primarily work with ES6 modules. When using namespaces:
- Use tsc to compile to your target module format
- Ensure output matches your bundler's expectations
- Consider using rollup-plugin-typescript2 or ts-loader for Webpack
### Migration Path
If maintaining namespaces is problematic, consider this migration path:
1. Convert one namespace at a time to ES6 modules
2. Update imports from import * as Namespace to named imports
3. Use codemods or search/replace for bulk changes
4. Test thoroughly as module resolution differs
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