This TypeScript error occurs when you try to import something that hasn't been exported from the source module. The fix involves either adding the missing export declaration in the source file or using the correct import syntax (named vs default export).
The "'X' cannot be imported, as it is not exported from 'Y'" error (TS2305) appears when TypeScript's type checker detects that you're trying to import an identifier that isn't actually exported from the module you're importing from. TypeScript follows ES Module standards where every file containing top-level import or export statements is considered a module, and items must be explicitly exported to be imported elsewhere. This error prevents runtime errors by catching missing exports at compile time. Common scenarios include: 1. **Missing export keyword**: You declared a variable, function, or type but forgot to add `export` before it 2. **Wrong import syntax**: Using named import syntax `{ X }` for a default export, or vice versa 3. **Type-only imports**: Using `import type { X }` for a value that needs runtime access 4. **Module format confusion**: Mixing ES modules and CommonJS export patterns 5. **Package.json exports restrictions**: The package restricts which subpaths can be imported
First, verify that the item you're trying to import is actually exported from the source module:
// In module Y.ts - CHECK THIS FILE
// ❌ WRONG - missing export keyword
const someValue = 42;
function helper() { return "help"; }
type MyType = { id: string };
// ✅ CORRECT - add export keyword
export const someValue = 42;
export function helper() { return "help"; }
export type MyType = { id: string };
// ✅ CORRECT - export at the end
const someValue = 42;
function helper() { return "help"; }
type MyType = { id: string };
export { someValue, helper, type MyType };Open the source file (Y.ts in the error message) and look for the identifier. If it's not exported, add the export keyword before it or add it to an export list.
Ensure you're using the correct import syntax for how the item is exported:
// In module Y.ts
export default function mainFunction() { /* ... */ } // Default export
export const helper = () => { /* ... */ }; // Named export
// In importing file
// ❌ WRONG - using named import for default export
import { mainFunction } from "./Y";
// ✅ CORRECT - default import for default export
import mainFunction from "./Y";
// ✅ CORRECT - named import for named export
import { helper } from "./Y";
// ✅ CORRECT - mixed imports
import mainFunction, { helper } from "./Y";Check the source module to see if it uses export default (default export) or export const/function/class (named export).
If you're importing a type, ensure you're using the correct syntax:
// In module Y.ts
export type User = { id: string; name: string }; // Type export
export const createUser = () => ({ id: "1", name: "Alice" }); // Value export
// In importing file
// ✅ CORRECT - import type for types
import type { User } from "./Y";
// ✅ CORRECT - regular import for values
import { createUser } from "./Y";
// ✅ CORRECT - mixed import
import { createUser, type User } from "./Y";
// ❌ WRONG - trying to use type as value
import type { User } from "./Y";
const user: User = createUser(); // ✅ OK - type position
console.log(User); // ❌ Error - value positionRemember: import type imports can only be used in type positions, not as runtime values.
If importing from an npm package, check if the package.json has an "exports" field that restricts imports:
// In the package's package.json
{
"name": "some-package",
"exports": {
".": "./dist/index.js",
"./utils": "./dist/utils.js" // Only these paths are allowed
}
}// ✅ These will work
import { something } from "some-package";
import { util } from "some-package/utils";
// ❌ These may fail if not in exports field
import { internal } from "some-package/dist/internal.js";
import { secret } from "some-package/src/secret.ts";Solution: Only import from paths listed in the "exports" field, or contact the package maintainer to add the export.
TypeScript files without any import or export statements are treated as scripts, not modules. Add an export statement:
// In Y.ts - currently a script (no imports/exports)
const value = 42;
function helper() { return "help"; }
// ❌ This file won't allow imports because it's not a module
// ✅ Add any export to make it a module
export const value = 42;
function helper() { return "help"; }
// OR add an empty export
const value = 42;
function helper() { return "help"; }
export {}; // Makes file a module while not exporting anythingFiles need at least one top-level import or export to be considered ES modules.
Module imports are case-sensitive. Check for typos:
// In module Y.ts
export const myValue = 42;
export const MyComponent = () => <div>Hello</div>;
// In importing file
// ❌ WRONG - case mismatch
import { myvalue } from "./Y"; // Should be myValue
import { mycomponent } from "./Y"; // Should be MyComponent
// ❌ WRONG - typo
import { myVal } from "./Y"; // Should be myValue
// ✅ CORRECT - exact match
import { myValue, MyComponent } from "./Y";Use your IDE's autocomplete to avoid typos. Most editors will suggest available exports as you type.
### Re-exporting (Barrel Files)
You can create barrel files that re-export from multiple modules:
// In index.ts (barrel file)
export { User } from "./models/User";
export { Product } from "./models/Product";
export { formatDate } from "./utils/date";
export { logger } from "./utils/logger";
// Now you can import from the barrel
import { User, formatDate } from "./index";### Namespace Imports for Type-Only Access
When using namespace imports, TypeScript-specific declarations are only accessible in type positions:
import * as mod from "./module.js";
// ❌ Error - trying to access type as value
console.log(mod.SomeType);
// ✅ OK - using type in type position
const x: mod.SomeType = { /* ... */ };
// ✅ Better - import type directly
import type { SomeType } from "./module.js";### Dynamic Imports
Dynamic imports (import()) have different error behavior:
// Static import - fails at compile time
import { missing } from "./module"; // ❌ TS2305
// Dynamic import - fails at runtime
const module = await import("./module");
module.missing(); // ❌ Runtime error, not compile error### CommonJS Interoperability
When importing from CommonJS modules in ES modules:
// CommonJS module (module.cjs or .js with module.exports)
module.exports = { hello: "world" };
// ES module import
// ❌ May fail - CommonJS doesn't have named exports
import { hello } from "./module.cjs";
// ✅ Use default import
import mod from "./module.cjs";
console.log(mod.hello);
// ✅ Or use require() in .cjs/.mjs files
const mod = require("./module.cjs");Configure esModuleInterop in tsconfig.json for better CommonJS compatibility.
### Checking What's Exported
Use TypeScript's language server to see available exports:
# In VS Code, hover over import to see available exports
import { /* hover here */ } from "./module";
# Or check with tsc
npx tsc --noEmit --listFiles | grep "module.ts"### Export Maps for Conditional Exports
Modern packages use export maps for different environments:
{
"exports": {
".": {
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js",
"types": "./dist/types/index.d.ts"
},
"./utils": {
"import": "./dist/esm/utils.js",
"require": "./dist/cjs/utils.js"
}
}
}TypeScript will use the "types" entry when available.
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