Fix TS2305: Module Has No Exported Member in TypeScript
TS2305 says the export you're importing doesn't exist under that name. The cause is almost always one of: a typo, default-vs-named confusion, a CJS/ESM interop mismatch, or @types drifting from the runtime package. Each has a precise fix.
TypeScript rejects an import you're sure is correct:
Module '"./user-service"' has no exported member 'getUser'. (2305)TS2305 means exactly what it says: the module does not export that name. The cause is almost always one of four things, and each has a precise fix. This guide walks them in order of frequency.
Cause A — wrong name, typo, or rename (most common)#
The named import must match an export exactly — case-sensitive.
// user-service.ts
export function getUser() {}
import { GetUser } from './user-service'; // TS2305 (wrong case)
import { getUser } from './user-service'; // correct
import { getUser as fetchUser } from './user-service'; // aliasedCause B — default vs named export mismatch#
Importing a default as named (or vice versa):
// default export: export default function foo() {}
import { foo } from './m'; // TS2305 — it's the default, not a named "foo"
import foo from './m'; // correct
// named export only: export const bar = 1;
import bar from './m'; // TS1192: has no default export
import { bar } from './m'; // correctSo TS2305 and its sibling TS1192 ("has no default export") are usually the same root: you guessed the wrong export shape. Open the module (or its .d.ts) and check.
Cause C — CommonJS / ESM interop#
A CommonJS package (module.exports = ... / export =) default-imported with interop off throws TS1259 or TS2497 ("can only be default-imported using the 'esModuleInterop' flag").
// tsconfig.json — the fix
{ "compilerOptions": { "esModuleInterop": true } }What esModuleInterop does (from the docs): with it off, import X from "moment" is checked as require("moment").default — which often doesn't exist. Turning it on changes the compiler's checking and emits helper shims (__importDefault, __importStar) so default/namespace imports of CommonJS work safely. It also automatically enables allowSyntheticDefaultImports.
The docs warn directly: "allowSyntheticDefaultImports without esModuleInterop should be avoided. It changes the compiler's checking behavior without changing the code emitted by tsc, allowing potentially unsafe JavaScript to be emitted."
If you can't change config, the namespace import is a safe workaround:
import * as React from 'react'; // no default neededCause D — a type-only export under verbatimModuleSyntax#
Single-file transpilers (Babel, esbuild, SWC) can't tell a type from a value, so under verbatimModuleSyntax you must use import type (errors TS1484/TS1485):
import type { User } from './types'; // type
import { createUser } from './api'; // value
export type { User }; // re-export a typeCause E — stale @types vs the runtime package#
If @types/foo is on a different version than foo, the typed export genuinely isn't in the installed .d.ts — a real TS2305. The source of truth is the .d.ts, not the JS.
npm ls foo @types/foo
npm i -D @types/foo@latest # or pin to match the runtime majormodule: "nodenext"/node16changes interop further and can supply a synthetic default withoutesModuleInteropin some checking modes — verify against the module-resolution docs if you're on those.verbatimModuleSyntax(TS1484/1485) needs TypeScript 5.0+ — older versions use different type-import rules.
Decision guide#
| You see | Likely cause | Fix |
|---|---|---|
| TS2305 on a named import | typo / wrong name | match the export exactly |
| TS2305 / TS1192 | default vs named | switch import X ↔ import { X } |
| TS1259 / TS2497 | CJS default import | esModuleInterop: true |
| TS1484 / TS1485 | type imported as value | import type |
| TS2305 on a typed lib | stale @types | realign versions |
Official references: esModuleInterop, allowSyntheticDefaultImports, ESM/CJS interop handbook, isolatedModules.
Related Articles#
- TypeScript Migration Guide: Moving a JS Codebase in 2026
- Fix TS7016: Could Not Find a Declaration File for Module
- Fix Next.js Build Error Module Not Found After Deploy
- Interfaces vs Types in TypeScript: 2026 Best Practices
Frequently Asked Questions#
How do I fix "Module has no exported member"?#
Confirm the export name and default-vs-named shape (import X vs import { X }). If it's a CommonJS package default-imported, enable esModuleInterop. If @types drifted from the runtime package, realign versions.
What does esModuleInterop actually do?#
With it off, import X from "cjs-mod" checks as require("cjs-mod").default, which often doesn't exist. On, it changes checking and emits interop shims so default/namespace CJS imports work — and it enables allowSyntheticDefaultImports.
Should I use allowSyntheticDefaultImports instead?#
Not alone. It only affects type-checking, not emitted JS — using it without esModuleInterop can emit unsafe code. Prefer esModuleInterop.
Frequently Asked Questions
One email a month — no fluff
RLS gotchas, Next.js cache debugging, and the one Supabase setting that bit me last month.
Continue Reading
Fix TS7016: Could Not Find Declaration File for Module
TS7016 fires when you import an untyped JavaScript module under noImplicitAny. The right fix is usually `npm i -D @types/X` — but sometimes the package already ships types, and sometimes you need to write a one-line declaration.
Fix TS2564: Property Has No Initializer in TypeScript
TS2564 fires when a class field is typed but never guaranteed to be set. The fix depends on WHY it's unset: a default value, constructor assignment, the definite-assignment `!`, or an optional `?`. Picking the wrong one hides real bugs.
Fix Next.js Module Not Found After Deploy or Production Build
Module not found errors only in production? Learn why Next.js builds fail after deploy and get 6 proven fixes that work on Vercel, AWS, and other platforms.
Browse by Topic
Find stories that matter to you.
