How to fix Cannot use namespace as a type in TypeScript
This error appears when you import a module using namespace import syntax (import * as X) and then try to use that namespace directly as a type annotation. TypeScript distinguishes between the imported namespace object and the types it contains, requiring you to access types via member notation or use typeof.
Quick fix
Fixes TS2709
import * as React from 'react';
// This fails:
const component: React = () => {}; // ERROR: Cannot use namespace 'React' as a type- Access specific types from the imported namespace
- Switch to named type imports
- Use typeof for the namespace value
- Fix module declaration conflicts
import * as React from 'react';// This fails:const component: React = () => {}; // ERROR: Cannot use namespace 'React' as a typeCannot use namespace as a type
What this error means
When you use TypeScript's namespace import syntax (`import * as X from 'module'`), you create a namespace object that contains all the exported values and types from that module. However, the namespace itself is not a type—it's a container. This error occurs specifically in import scenarios where developers attempt to use the imported namespace name directly as a type annotation. TypeScript enforces a strict separation between: 1. The namespace object (which exists at runtime as a value) 2. The types exported from the module (which exist only at compile-time) Common scenarios include importing a library with `import * as Library` and then trying to write `const x: Library = ...`, or importing types from a module declaration that creates a namespace. The compiler cannot determine which type you mean when you reference just the namespace name. The error code is TS2709, the same code used for general namespace-as-type errors, but import-specific cases have unique solutions.
Typical symptoms
- Error message 'Cannot use namespace X as a type' appears on lines with namespace imports
- The problematic code uses 'import * as X from' syntax followed by type annotation with X
- IDE shows the error immediately after trying to use the imported namespace name as a type
- Code fails to compile but the import statement itself doesn't show errors
- The error appears when migrating from individual imports to namespace imports
- Type checking works fine when using named imports but breaks with namespace imports
Common causes
- Using namespace import (import * as X) then referencing X directly as a type instead of X.TypeName (most common)
- Attempting to use typeof on a namespace that only exports type members with no runtime values
- Importing from a module with 'declare module' that creates an ambient namespace instead of a proper module
- Mixing namespace imports with type annotations in function signatures or variable declarations
- Library type definitions export a namespace structure but your code expects a direct type
- Using namespace imports with libraries that have inconsistent type/value exports
How to fix "Cannot use namespace as a type"
When using namespace imports, access the exported types using dot notation instead of using the namespace directly:
Problematic code:
import * as React from 'react';
// This fails:
const component: React = () => {}; // ERROR: Cannot use namespace 'React' as a typeSolution - access specific types:
import * as React from 'react';
// Access the specific type you need:
const component: React.FC = () => {}; // CORRECT
// Or for component props:
const MyComponent: React.FunctionComponent<{ name: string }> = ({ name }) => {
return <div>{name}</div>;
};The namespace import gives you access to all exported members, but you must specify which one you're using.
Instead of namespace imports, use named imports to directly import the types you need:
Before (namespace import - causes issues):
import * as express from 'express';
const app: express = express(); // ERRORAfter (named import - recommended):
import express, { Express, Request, Response } from 'express';
const app: Express = express(); // CORRECT
function handler(req: Request, res: Response) {
// Function implementation
}Named imports make it clear which types you're using and avoid namespace confusion.
If you need to reference the type of the entire imported namespace object (including all its members), use the typeof operator:
import * as utils from './utils';
// Wrong:
type UtilsType = utils; // ERROR: Cannot use namespace as a type
// Correct - use typeof:
type UtilsType = typeof utils; // This captures the type of the namespace object
// Now you can use it:
function processUtils(u: typeof utils) {
u.helper(); // Access methods from the namespace
}The typeof operator creates a type from the runtime value, capturing the structure of the namespace object.
If you have conflicting module declarations creating namespace-like behavior, clean up your type definitions:
Problematic setup:
// types.d.ts
declare module 'my-library'; // Creates ambient namespace
// app.ts
import * as MyLib from 'my-library';
type Lib = MyLib; // ERRORSolution - proper module declaration:
// types.d.ts - declare the actual exports
declare module 'my-library' {
export interface Config {
apiKey: string;
}
export function initialize(config: Config): void;
}
// app.ts - now you can import properly
import { Config, initialize } from 'my-library';
type LibConfig = Config; // CORRECTOr simply remove the declare module if the library has its own type definitions.
Some libraries export both a namespace and types. Handle these carefully by accessing nested types:
import * as d3 from 'd3';
// Wrong - using the entire namespace:
const scale: d3 = d3.scaleLinear(); // ERROR
// Correct - access the specific type constructor:
const scale: d3.ScaleLinear<number, number> = d3.scaleLinear();
// Or for function signatures:
type ScaleType = ReturnType<typeof d3.scaleLinear>;
const scale2: ScaleType = d3.scaleLinear();For complex library types, check the library's documentation for the correct type path or use ReturnType/Parameters utility types.
Advanced notes
### Namespace Imports vs Named Imports
TypeScript supports multiple import styles, each with trade-offs:
**Namespace imports (import * as X):**
- Creates a single object containing all exports
- Useful for large libraries with many exports
- Can cause this error if misused as a type
- More verbose when accessing members: X.Type vs Type
Named imports (`import { X, Y }`):
- Directly imports specific exports
- Better for tree-shaking (unused code elimination)
- Clearer intent in code
- Recommended for modern TypeScript
### Type-Only Namespace Imports (TypeScript 5.0+)
You can use type-only namespace imports to be explicit about importing only types:
import type * as Types from './types-only-module';
// This imports only types, no runtime values
type MyType = Types.SomeType; // Must access via namespace
// This would error if the module has no runtime exports:
const value = Types.someValue; // Error if Types is type-only### Barrel Exports and Re-exports
When creating barrel exports (index.ts files), be careful with namespace re-exports:
// api/index.ts - problematic
export * as models from './models'; // Creates a namespace
// usage.ts
import { models } from './api';
type User = models; // ERROR - models is a namespace
// Better approach:
// api/index.ts
export * from './models'; // Flat re-export
// usage.ts
import { User } from './api';
type UserType = User; // CORRECT### Module Augmentation vs Namespace
Be careful not to confuse module augmentation with namespace creation:
// Augmenting an existing module (correct):
declare module 'express' {
interface Request {
user?: User;
}
}
// Accidentally creating a namespace (problematic):
declare module 'express'; // Empty declaration creates namespace### TypeScript Compiler Options
The esModuleInterop and allowSyntheticDefaultImports compiler options affect how namespace imports work with CommonJS modules:
{
"compilerOptions": {
"esModuleInterop": true, // Enables better CommonJS interop
"allowSyntheticDefaultImports": true // Allows default imports
}
}With these enabled, you can often avoid namespace imports altogether:
// Without esModuleInterop:
import * as React from 'react'; // Namespace import needed
// With esModuleInterop:
import React from 'react'; // Default import worksFrequently asked questions
- What does "TS2709" mean?
- When you use TypeScript's namespace import syntax (import as X from 'module'), you create a namespace object that contains all the exported values and types from that module. However, the namespace itself is not a type—it's a container. This error occurs specifically in import scenarios where developers attempt to use the imported namespace name directly as a type annotation.
- How do I fix "TS2709"?
- This error appears when you import a module using namespace import syntax (import * as X) and then try to use that namespace directly as a type annotation. TypeScript distinguishes between the imported namespace object and the types it contains, requiring you to access types via member notation or use typeof.
- What causes "TS2709"?
- Using namespace import (import * as X) then referencing X directly as a type instead of X.TypeName (most common) Attempting to use typeof on a namespace that only exports type members with no runtime values Importing from a module with 'declare module' that creates an ambient namespace instead of a proper module
- Is the "TS2709" error serious?
- It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- 📚TypeScript Official Documentation
- 📖TypeScript Documentation - Namespaces(Official Docs)
- 📖TypeScript Documentation - Namespaces and Modules(Official Docs)
- 📖TypeScript Documentation - Modules Reference(Official Docs)
- 🐙
- 🐙