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.
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.
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.
### 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 worksFunction 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