How to fix Exported variable 'X' has or is using name 'Y' from external module 'Z' but cannot be named in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 8, 2025· 161 views

This TypeScript error (TS4023) occurs when generating declaration files and the compiler cannot properly reference types from external modules in your exported variables. It happens when you export a variable whose inferred type uses types from external modules that cannot be explicitly named in the generated .d.ts file.

Quick fix

Fixes TS4023

// BEFORE - Type is inferred, causes TS4023
import { DataGrid } from '@mui/x-data-grid';

export const myGrid = DataGrid({ /* config */ });
// Error: Exported variable 'myGrid' has or is using name 'DataGridComponent'

// AFTER - Explicitly typed
import { DataGrid, DataGridProps } from '@mui/x-data-grid';

export const myGrid: React.ComponentType<DataGridProps> = DataGrid({ /* config */ });
  1. Add explicit type annotations to exported variables
  2. Import the type that cannot be named
  3. Use type-only exports for re-exported types
  4. Ensure all composite types are exported
typescript — error
// BEFORE - Type is inferred, causes TS4023
import { DataGrid } from '@mui/x-data-grid';
export const myGrid = DataGrid({ /* config */ });
// Error: Exported variable 'myGrid' has or is using name 'DataGridComponent'
// AFTER - Explicitly typed
import { DataGrid, DataGridProps } from '@mui/x-data-grid';
export const myGrid: React.ComponentType<DataGridProps> = DataGrid({ /* config */ });
Exported variable 'X' has or is using name 'Y' from external module 'Z' but cannot be named

What this error means

The TS4023 error appears when TypeScript is generating declaration files (enabled via `declaration: true` or `composite: true` in tsconfig.json) and encounters an exported variable that uses types from external modules in a way that cannot be properly represented in the generated .d.ts file. TypeScript needs to create a public type signature for every exported value. When you export a variable whose type is inferred from external module types, the compiler must decide how to express that type in the declaration file. If the type includes references to types that aren't explicitly imported or can't be publicly named, TypeScript cannot generate a valid declaration file. This error is fundamentally about the boundary between your module's public API and its internal implementation. TypeScript is warning you that consumers of your module won't be able to see accurate type information for this exported variable. Common scenarios include: 1. **Inferred types from re-exports**: Exporting objects or arrays that contain instances of classes from external modules 2. **Complex type inference**: TypeScript infers a type that includes private or non-exported types from dependencies 3. **Declaration file generation**: The error only appears when TypeScript tries to generate .d.ts files, not during regular compilation In TypeScript 2.9+, many cases are handled automatically using import type syntax in generated declarations, but complex scenarios still trigger this error.

Typical symptoms

  • Compilation fails only when declaration: true is enabled in tsconfig.json
  • Error message references TS4023 with specific variable and module names
  • Error appears only during declaration file generation, not during regular builds
  • Error mentions 'but cannot be named' at the end of the message
  • Build succeeds when declaration option is disabled
  • IDE may show error on exported const/let/var declarations
  • Error occurs in library projects using composite: true for project references

Common causes

  1. Exporting a variable with an inferred type that references unexported types from external modules
  2. Re-exporting objects or classes from external modules without explicit type annotations
  3. Using heavily inferred types that indirectly reference external module types
  4. Exporting variables that contain instances of classes from dependencies
  5. Type inference creates circular dependencies between modules in declaration files
  6. Using generic types that resolve to external module types without explicit annotations
  7. Exporting default objects that aggregate classes/types from multiple external modules

How to fix "Exported variable 'X' has or is using name 'Y' from external module 'Z' but cannot be named"

1Add explicit type annotations to exported variables

The most direct solution is to explicitly type your exported variables instead of relying on type inference:

typescript
// BEFORE - Type is inferred, causes TS4023
import { DataGrid } from '@mui/x-data-grid';

export const myGrid = DataGrid({ /* config */ });
// Error: Exported variable 'myGrid' has or is using name 'DataGridComponent'

// AFTER - Explicitly typed
import { DataGrid, DataGridProps } from '@mui/x-data-grid';

export const myGrid: React.ComponentType<DataGridProps> = DataGrid({ /* config */ });

For complex objects:

typescript
// BEFORE
import { someFunction } from 'external-lib';

export const config = {
  handler: someFunction(),
  options: { /* ... */ }
};

// AFTER
import { someFunction, HandlerType } from 'external-lib';

interface ConfigType {
  handler: HandlerType;
  options: { /* ... */ };
}

export const config: ConfigType = {
  handler: someFunction(),
  options: { /* ... */ }
};

This gives TypeScript explicit type information to include in the declaration file.

2Import the type that cannot be named

Sometimes the error occurs because TypeScript knows about a type but hasn't imported it in your file. Explicitly import the type mentioned in the error:

typescript
// Error message says:
// "has or is using name 'NumberKeywords' from external module 'ajv/dist/types/json-schema'"

// BEFORE - Type used but not imported
import Ajv from 'ajv';

export const validator = new Ajv();

// AFTER - Import the type explicitly
import Ajv from 'ajv';
import type { NumberKeywords } from 'ajv/dist/types/json-schema';

export const validator = new Ajv();

Even if you don't reference NumberKeywords directly in your code, importing it allows TypeScript to reference it in the generated declaration file.

You can also use type imports to avoid runtime overhead:

typescript
import type { SomeType } from 'external-module';
import { someFunction } from 'external-module';

export const result: ReturnType<typeof someFunction> = someFunction();
3Use type-only exports for re-exported types

If you're re-exporting types or objects from external modules, use explicit type exports:

typescript
// BEFORE - Re-exporting without types
export { default as MyComponent } from 'external-lib';

// AFTER - Explicit type export
export type { ComponentProps } from 'external-lib';
export { default as MyComponent } from 'external-lib';

For aggregating exports:

typescript
// BEFORE
import * as Utils from './utils';
export const helpers = Utils;

// AFTER
export type * as Utils from './utils';
export * from './utils';

// OR with explicit namespace
import type * as UtilsType from './utils';
import * as UtilsImpl from './utils';

export const helpers: typeof UtilsType = UtilsImpl;
4Ensure all composite types are exported

If your exported variable uses a complex type, ensure all parts of that type are properly exported from their source modules:

typescript
// external-lib/index.ts
// BEFORE - InternalConfig not exported
interface InternalConfig {
  setting: string;
}

export function createHandler(config: InternalConfig) {
  return { /* ... */ };
}

// AFTER - Export all types used in public API
export interface InternalConfig {
  setting: string;
}

export function createHandler(config: InternalConfig) {
  return { /* ... */ };
}

In your consuming code:

typescript
import { createHandler } from 'external-lib';
import type { InternalConfig } from 'external-lib';

export const handler: ReturnType<typeof createHandler> = createHandler({
  setting: 'value'
});
5Update TypeScript to version 2.9 or later

TypeScript 2.9 introduced better handling of this error by supporting import types in declaration files:

bash
# Check your TypeScript version
npx tsc --version

# Update to latest TypeScript
npm install --save-dev typescript@latest

# Or specific version (5.x recommended)
npm install --save-dev typescript@^5.0.0

After updating, TypeScript will automatically use import("module").Type syntax in generated declarations:

typescript
// Your source code
import { Hash } from 'crypto';
export const hash = createHash('sha256');

// Generated declaration (TypeScript 2.9+)
export declare const hash: import("crypto").Hash;

This resolves many cases of TS4023 without requiring manual type annotations. Check your tsconfig.json to ensure you're using modern compiler options:

json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "esnext",
    "moduleResolution": "bundler",
    "declaration": true
  }
}
6Use ReturnType or typeof for complex inferred types

For variables whose types are based on function returns or complex expressions, use TypeScript utility types:

typescript
// BEFORE
import { createComplexObject } from 'external-lib';

export const instance = createComplexObject({ /* config */ });

// AFTER - Using ReturnType
import { createComplexObject } from 'external-lib';

export const instance: ReturnType<typeof createComplexObject> =
  createComplexObject({ /* config */ });

For class instances:

typescript
// BEFORE
import { SomeClass } from 'external-lib';

export const instance = new SomeClass();

// AFTER - Using InstanceType
import { SomeClass } from 'external-lib';

export const instance: InstanceType<typeof SomeClass> = new SomeClass();

For objects with known shape:

typescript
import { processData } from 'external-lib';

type ProcessedData = {
  result: string;
  metadata: Record<string, unknown>;
};

export const data: ProcessedData = processData(input);

Advanced notes

### Understanding Declaration File Generation

When TypeScript generates declaration files, it must create a complete public API description without implementation details. The compiler faces challenges when:

1. Visibility boundaries: A public export references a type that isn't public
2. Module boundaries: Types cross module boundaries in complex ways
3. Inference chains: Type inference creates long chains through multiple modules

### Project References and Composite Mode

This error is particularly common in monorepos using project references (composite: true):

json
// tsconfig.json
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true
  }
}

Composite projects require perfect declaration files for cross-project type checking. Solutions:

1. Explicit API boundaries: Define clear interfaces for cross-package communication
2. Barrel exports: Use index.ts files to re-export with explicit types
3. Type-only dependencies: Use import type for type-only references

### Module Detection and Type Imports

TypeScript 4.7+ introduced moduleDetection which affects how files are treated:

json
{
  "compilerOptions": {
    "moduleDetection": "force"
  }
}

This forces all files to be modules, requiring explicit imports/exports. This can help by making type dependencies explicit.

### Working with Third-Party Libraries

Some libraries have imperfect type definitions. Workarounds:

Option 1: Augment module declarations

typescript
// types/module-augmentation.d.ts
import 'problematic-library';

declare module 'problematic-library' {
  export interface PublicConfig {
    // Add missing types
  }
}

Option 2: Create wrapper functions

typescript
// Instead of exporting library objects directly
import { ThirdPartyClass } from 'library';

// Create a typed wrapper
export interface MyWrapperConfig {
  // Your explicit config type
}

export function createWrapper(config: MyWrapperConfig) {
  return new ThirdPartyClass(config);
}

### Declaration Reference Directives

For complex multi-package scenarios, use triple-slash directives:

typescript
/// <reference types="dependency-package" />

export const value: DependencyType = createValue();

This ensures TypeScript includes necessary type information in declaration output.

### Debugging Declaration Generation

See what TypeScript is generating:

bash
# Generate declarations and inspect
npx tsc --declaration --emitDeclarationOnly

# Check the .d.ts file
cat dist/index.d.ts

Look for:
- Missing type imports
- any types (red flag for lost type information)
- Incomplete type signatures

### Performance Implications

Explicit type annotations have benefits beyond fixing TS4023:

1. Faster type checking: Compiler doesn't need to infer complex types
2. Better error messages: Errors appear at declaration site, not call site
3. Intentional API design: Forces you to think about your public API
4. Easier refactoring: Type changes show immediate impact

### Alternative: Disable Declaration Generation Temporarily

If you're building an application (not a library), you may not need declarations:

json
{
  "compilerOptions": {
    "declaration": false
  }
}

However, this prevents using project references and can impact IDE performance in large projects.

Frequently asked questions

What does "TS4023" mean?
ts file. TypeScript needs to create a public type signature for every exported value. When you export a variable whose type is inferred from external module types, the compiler must decide how to express that type in the declaration file.
How do I fix "TS4023"?
This TypeScript error (TS4023) occurs when generating declaration files and the compiler cannot properly reference types from external modules in your exported variables. It happens when you export a variable whose inferred type uses types from external modules that cannot be explicitly named in the generated .d.ts file.
What causes "TS4023"?
Exporting a variable with an inferred type that references unexported types from external modules Re-exporting objects or classes from external modules without explicit type annotations Using heavily inferred types that indirectly reference external module types
Is the "TS4023" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading