This TypeScript error occurs when importing a namespace without using the proper "* as" syntax. Namespaces are TypeScript's way to organize code and must be imported with the "import * as" pattern. The fix involves updating your import statement to use the correct syntax.
The "Namespace import 'X' requires '* as' syntax" error occurs when you try to import a TypeScript namespace using incorrect syntax. TypeScript namespaces are a legacy module system that predates ES6 modules, and they have specific import requirements. In TypeScript, namespaces are declared using the `namespace` or `module` keyword and can contain functions, classes, interfaces, and other declarations. Unlike ES6 modules which use named exports, namespaces must be imported as a whole object using the `import * as` syntax. This error typically appears when: 1. You're trying to import from a .d.ts file that uses namespace declarations 2. You're working with legacy TypeScript code or libraries that haven't migrated to ES6 modules 3. You're importing from DefinitelyTyped packages that use namespace declarations The error message is TypeScript's way of telling you that you need to treat the namespace as a single object rather than trying to destructure it or import specific members directly.
First, identify which import is causing the error. Look for imports from files that use the namespace or module keyword:
// Error example - trying to import namespace members directly
import { SomeFunction, SomeClass } from 'some-namespace-library';
// Error: Namespace import 'some-namespace-library' requires '* as' syntax
// Check the source file to confirm it's a namespace
// Look for declarations like:
namespace SomeNamespace {
export function SomeFunction() { /* ... */ }
export class SomeClass { /* ... */ }
}The error message will tell you which namespace requires the "* as" syntax.
Change your import statement to use the correct namespace import syntax:
// WRONG - ES6 style import for namespace
import { SomeFunction, SomeClass } from 'some-namespace-library';
// CORRECT - namespace import with "* as"
import * as SomeNamespace from 'some-namespace-library';
// Now access members through the namespace object
SomeNamespace.SomeFunction();
const instance = new SomeNamespace.SomeClass();If you need to use the members frequently, you can create local aliases:
import * as SomeNamespace from 'some-namespace-library';
const SomeFunction = SomeNamespace.SomeFunction;
const SomeClass = SomeNamespace.SomeClass;
// Now use them directly
SomeFunction();
new SomeClass();Some libraries export both namespaces and modules. Check the library's type definitions:
// Example of mixed exports in a .d.ts file
declare module 'mixed-library' {
// ES6 module exports
export function moduleFunction(): void;
export class ModuleClass {}
// Namespace export
export namespace Utils {
export function helper(): void;
}
}
// Correct imports for mixed library
import { moduleFunction, ModuleClass } from 'mixed-library'; // ES6 imports work
import * as Utils from 'mixed-library/Utils'; // Namespace import for UtilsIf the library has a namespace inside a module, you may need to import it separately.
Ensure your TypeScript configuration supports namespace resolution:
{
"compilerOptions": {
"module": "commonjs", // or "amd", "system", "umd" for namespaces
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
}
}For namespace-heavy projects, you might need:
{
"compilerOptions": {
"module": "commonjs",
"target": "es5", // Namespaces work better with older targets
"lib": ["es5", "dom"],
"outDir": "./dist",
"rootDir": "./src"
}
}After updating tsconfig.json, restart your TypeScript server.
If you control the codebase, consider migrating from namespaces to ES6 modules:
// OLD - namespace approach
namespace Utilities {
export function formatDate(date: Date): string {
return date.toISOString();
}
export function parseString(str: string): number {
return parseInt(str, 10);
}
}
// NEW - ES6 module approach
// utilities.ts
export function formatDate(date: Date): string {
return date.toISOString();
}
export function parseString(str: string): number {
return parseInt(str, 10);
}
// Import becomes simpler
import { formatDate, parseString } from './utilities';Benefits of ES6 modules:
- Standard JavaScript (works in browsers and Node.js)
- Better tree-shaking for bundlers
- Clearer dependency structure
- No need for "* as" syntax
Some libraries augment global namespaces. For these, you don't need imports at all:
// Library declares global namespace
declare global {
namespace MyGlobalLib {
function doSomething(): void;
const version: string;
}
}
// Usage - no import needed
MyGlobalLib.doSomething();
console.log(MyGlobalLib.version);If you see "Cannot find name" errors for global namespaces, ensure the type definitions are included:
{
"compilerOptions": {
"typeRoots": ["./node_modules/@types"],
"types": ["node", "my-global-library"]
}
}### Understanding TypeScript Namespaces vs Modules
Namespaces (formerly "internal modules"):
- Declared with namespace or module keyword
- Organize code within a single global scope
- Can be split across files using /// <reference path="..." />
- Compiled to objects in output JavaScript
- Best for: Legacy code, browser libraries, code sharing across files without module loaders
ES6 Modules (formerly "external modules"):
- Each file is its own module
- Use import/export syntax
- Supported natively in modern JavaScript
- Better for: New projects, Node.js, bundlers like webpack/Vite
### Migration Path from Namespaces to Modules
1. Convert namespace to module file:
// Before: utils.ts
namespace Utils {
export function helper() { /* ... */ }
}
// After: utils.ts
export function helper() { /* ... */ }2. Update imports:
// Before
/// <reference path="utils.ts" />
Utils.helper();
// After
import { helper } from './utils';
helper();3. Update tsconfig.json:
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "node"
}
}### Common Namespace Patterns in Wild
1. jQuery-style plugins:
// jQuery UI type definitions
interface JQuery {
datepicker(options?: any): JQuery;
}2. Global utility libraries:
// Lodash before ES6 modules
declare module _ {
interface LoDashStatic {
chunk<T>(array: T[], size?: number): T[][];
}
}3. Node.js built-ins (legacy):
// Old Node.js type definitions
declare module "fs" {
export function readFileSync(path: string): Buffer;
}### Debugging Namespace Issues
Use tsc --traceResolution to see how TypeScript resolves namespace imports:
npx tsc --traceResolution | grep -A5 -B5 "namespace"Check the actual JavaScript output to understand how namespaces are compiled:
npx tsc --outDir ./temp && cat ./temp/your-file.js### Compatibility with Bundlers
webpack: Namespaces work but may require explicit file references
Rollup: Better with ES6 modules; namespaces may need plugins
esbuild: Supports namespaces but optimized for ES6 modules
Vite: Primarily ES6 modules; namespaces in dependencies work fine
### When to Keep Namespaces
Despite being legacy, namespaces are still useful for:
- Maintaining compatibility with existing codebases
- Browser libraries that need to work without module bundlers
- Projects that share code via <script> tags
- Augmenting global objects (window, document, etc.)
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