TS2305Semantic Error
Since TS 1.0

Fix TS2305: Module Has No Exported Member

Learn why TypeScript throws TS2305 when an import names a member a module does not export, and how to fix moved APIs, barrel files and stale types.

error TS2305: Module 'X' has no exported member 'Y'

What This Error Means

TypeScript error TS2305 means your import found the module but not the member. The specifier resolved to a real file, the compiler read that file's export table, and the name you asked for was not on it.

That distinction matters, because it rules out a whole class of suspects. Resolution succeeded, so this is not a missing package, a broken relative path or an unmapped alias — those produce TS2307. The compiler got all the way to the export list and came back empty-handed. Which file it read still depends on moduleResolution, on paths, and on the package's own types and exports fields, so "the export list" is not always the list you are looking at in your editor.

// The general shape of the error:
// Module '"./services/orders"' has no exported member 'getOrders'.
//         ~~~~~~~~~~~~~~~~~~                          ~~~~~~~~~~
//         this file was found                         this name was not in it

TypeScript also has three more specific diagnostics that take precedence, which is why a plain TS2305 is a stronger signal than it looks. If the module has a default export you get TS2614 instead ("Did you mean to use import X from …?"). If a similarly spelled export exists you get TS2724 ("Did you mean fetchOrders?"). If the name is declared in the file but never exported you get TS2459. Only when none of those apply — the name is genuinely nowhere in the module's public surface — does the compiler fall back to TS2305. So this error usually means wrong module, wrong version, or wrong name entirely, not a small slip. The message text has not changed since TypeScript 1.0.

Common Causes

1. The API Moved or Was Renamed Between Versions

The single most common source of TS2305 is following a tutorial written against a different release of the package. Exports get relocated to a subpath, or deprecated aliases get deleted in a major bump, and the import line that used to work now points at a module that no longer owns that name.

// ❌ Broken
import { renderToString } from "react-dom"
//       ~~~~~~~~~~~~~~ Error: Module '"react-dom"' has no exported member 'renderToString'.
import type { ReactChild } from "react"
//            ~~~~~~~~~~ Error: Module '"react"' has no exported member 'ReactChild'.
 
export const markup = renderToString(null)
export type Cell = ReactChild
// ✅ Fixed — import from where the API actually lives now
import { renderToString } from "react-dom/server"
import type { ReactNode } from "react"
 
export const markup = renderToString(null)
export type Cell = ReactNode

renderToString has always been server-only and lives in the react-dom/server entry point. ReactChild is different: it was a real export of @types/react for years and was removed in the React 19 typings, where ReactNode covers the same ground. Both fail with the same code, and both are answered the same way — check the package's changelog or release notes for the version you actually have installed, not the version the blog post was written against.

2. A Barrel File That Never Re-Exported the Symbol

Barrel modules (orders/index.ts re-exporting a folder) are a favourite place for this error to hide. You add a new type to orders/summary.ts, import it through the barrel, and the barrel knows nothing about it. The symbol is exported — just not by the module you are importing from.

// orders/summary.ts
export interface OrderSummary {
  orderId: string
  total: number
}
 
// orders/index.ts
export { fetchOrders } from "./fetch"
 
// ❌ Broken — app.ts
import { fetchOrders, OrderSummary } from "./orders"
//                    ~~~~~~~~~~~~ Error: Module '"./orders"' has no exported member 'OrderSummary'.
 
export const ids: string[] = fetchOrders()
export const empty: OrderSummary[] = []
// ✅ Fixed — add the re-export to the barrel
// orders/index.ts
export { fetchOrders } from "./fetch"
export type { OrderSummary } from "./summary"
 
// app.ts
import { fetchOrders, type OrderSummary } from "./orders"
 
export const ids: string[] = fetchOrders()
export const empty: OrderSummary[] = []

Use export type (and import type, or an inline type modifier) for anything that only exists at compile time. Under isolatedModules — which Next.js, Vite and esbuild all require — a plain export { OrderSummary } in a barrel is a separate error, because the transpiler cannot tell whether to emit a runtime re-export.

3. A Name That Is Wrong, With No Near Match

If you misspell an export by a character or two, TypeScript is generous and gives you TS2724 with a suggestion. TS2305 is what you get when the name you invented is far enough from anything real that the compiler has nothing to suggest — typically a guess based on a naming convention the codebase does not use.

// services/orders.ts exports fetchOrders and fetchOrderById
 
// ❌ Broken
import { getOrders } from "./services/orders"
//       ~~~~~~~~~ Error: Module '"./services/orders"' has no exported member 'getOrders'.
 
export const ids: string[] = getOrders()
// ✅ Fixed — use the name the module actually exports
import { fetchOrders } from "./services/orders"
 
export const ids: string[] = fetchOrders()

The fastest way to see the real list is to type import { } from "./services/orders" and trigger completion inside the braces, or to Cmd-click (Ctrl-click) the specifier and read the file. Guessing a second time is rarely faster than looking.

4. The Build Resolved a Stale or Duplicate Copy

This is the version that wastes an afternoon: the member is right there in the source, and the compiler still refuses. That happens when the module specifier resolves to a different file than the one you have open — a workspace package whose types field points at a dist/index.d.ts that was built before you added the export, or a second copy of a types package hoisted into a different node_modules.

// node_modules/@acme/orders/package.json → "types": "dist/index.d.ts"
// src/index.ts has OrderSummary; dist/index.d.ts was built before it was added
 
// ❌ Broken
import { fetchOrders, type OrderSummary } from "@acme/orders"
//                         ~~~~~~~~~~~~ Error: Module '"@acme/orders"' has no exported member 'OrderSummary'.
 
export const ids: string[] = fetchOrders()
export const rows: OrderSummary[] = []
# ✅ Fixed — rebuild the dependency so its declarations match its source
npm run build --workspace @acme/orders
 
# and if the culprit is two copies of the same types package:
npm ls @types/react            # shows every version in the tree
npm i -D @types/react@latest   # or pin one copy via overrides / resolutions

The same symptom shows up with moduleResolution set to node16 or bundler when a package's exports map sends the types condition to a different declaration file than the old main-based lookup did. If a member disappeared right after you changed that setting, that is where to look.

How to Fix It

  1. Go to the definition before you change anything. Cmd-click (Ctrl-click) the module specifier and read the exports of the file that opens. If it is not the file you expected — a dist/*.d.ts, a second copy under a nested node_modules — you have found the real bug, and no amount of editing the import will fix it.

  2. Check the version you actually installed. npm ls <package> prints the resolved version and any duplicates. Compare it against the changelog: exports get moved to subpaths (react-dom to react-dom/server) and deprecated aliases get deleted in majors (ReactChild in the React 19 typings). Import from the new location rather than pinning an old version.

  3. Add the missing re-export. For a barrel, add export { thing } from "./file" — or export type { Thing } from "./file" for anything type-only, which isolatedModules requires. If the symbol is declared in the target file but has no export keyword at all, you will be looking at TS2459 rather than TS2305; add the keyword.

  4. Rebuild and restart before you debug further. Composite projects and workspace packages serve declarations from their build output, so a stale dist produces an error that no source change can clear. Rebuild the dependency, then run TypeScript: Restart TS Server from the editor command palette — the language service caches resolution results and will keep reporting the old export list.

  5. Do not paper over it with declare module or as any. Writing an ambient declaration that re-declares the member, or importing the whole module and casting it, silences TS2305 by asserting something the runtime will not honour — the property is still undefined when the code executes. Deduplicate your type packages with overrides (npm) or resolutions (yarn/pnpm), keep workspace builds wired into your dev script, and the error stops recurring on its own.

FAQ

What causes TypeScript error TS2305?

TS2305 fires when module resolution succeeded but the export lookup did not: the specifier pointed at a real file, and the name in your import braces was not in that file's export list. The four usual triggers are an API that moved to a subpath or was removed in a newer release, a barrel index.ts that was never updated to re-export a new symbol, a name that is outright wrong, and a build that resolved a stale or duplicated copy of the declarations. Because TypeScript prefers more specific diagnostics when it can, reaching plain TS2305 tells you the name is genuinely absent from that module — not merely misspelled.

Why does TS2305 appear when the member is definitely exported?

Because the compiler is reading a different file than you are. The usual culprits are a workspace package whose types entry points at a dist/index.d.ts built before the export existed, two copies of the same @types package at different depths in node_modules, and a path that differs from the real filename only in casing. Start with Go to Definition on the specifier and confirm which file opens, then run npm ls <package> to look for duplicates. If the file is a build artifact, rebuild the dependency and restart the TS server — the language service caches the old export list and will otherwise keep showing the error after you have fixed it.

How is TS2305 different from TS2614 and TS2307?

They mark three different stages of the same import. TS2307 is a resolution failure: the module was never found, so the export list was never read. TS2305 means the module was found but the name is not on its export list. TS2614 replaces TS2305 in one specific case — the module has a default export — and tells you to write import fetchOrders from "./orders" instead of destructuring braces, which is by far the most common real-world variant of "has no exported member". Two more siblings sit alongside it: TS2724 when a close spelling exists, and TS2459 when the identifier is declared in the module but not exported. Read which code you actually got before you start editing, because each one points at a different fix.

Related Errors

Practice This

Browse all TypeScript practice challenges to keep sharpening your type-level skills.

Share this reference

Become a TypeScript Pro

Track your progress through 100+ hands-on challenges. Free, sign in with GitHub.

Or start solving right away: explore all TypeScript challenges