This TypeScript error occurs when trying to import a default export from a module that doesn't have one. The module might use named exports instead, or the export configuration may be incorrect. Fixes include using named imports, checking module's export structure, or configuring esModuleInterop.
The "Module has no exported member 'default'" error (TS2305) happens when TypeScript cannot find a default export in the module you're importing from. This typically occurs when: 1. **Module uses named exports only**: The module exports individual functions/classes using `export function` or `export class` but doesn't have a `export default`. 2. **Incorrect import syntax**: Using `import X from "module"` when the module only has named exports like `export { something }`. 3. **CommonJS module with module.exports**: Some CommonJS modules use `module.exports = something` which TypeScript may interpret differently based on `esModuleInterop` settings. 4. **Mixed module systems**: Confusion between ES modules (import/export) and CommonJS (require/module.exports). TypeScript needs to match the import syntax with the actual export structure of the module. When you use `import X from "module"`, TypeScript looks for a `export default X` or equivalent in the target module. If it doesn't find one, you get this error.
First, examine what the module actually exports. Look at its source or type definitions:
// If module has named exports like this:
export function calculate() { /* ... */ }
export const PI = 3.14;
export class Calculator { /* ... */ }
// You CANNOT import it like this:
import MyModule from "./calculator"; // ERROR: No default export
// Instead use named imports:
import { calculate, PI, Calculator } from "./calculator";Check the module's documentation or type definitions (.d.ts files) to see its export structure. In VS Code, you can hover over the import to see available exports.
If the module only has named exports, import the specific members you need:
// Module: math-utils.ts
export function add(a: number, b: number) { return a + b; }
export function multiply(a: number, b: number) { return a * b; }
// WRONG - trying to import default
import mathUtils from "./math-utils"; // ERROR
// CORRECT - import named exports
import { add, multiply } from "./math-utils";
// CORRECT - import everything as namespace
import * as mathUtils from "./math-utils";
mathUtils.add(1, 2);For third-party packages, check their documentation for correct import syntax.
For CommonJS modules that use module.exports = something, enable esModuleInterop:
{
"compilerOptions": {
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
}
}These settings allow TypeScript to treat CommonJS modules as if they have default exports:
// With esModuleInterop: true
import express from "express"; // Works even though express uses module.exports
// Compiled to: const express = require("express").default || require("express")
// Without esModuleInterop: true
import * as express from "express"; // Must use namespace import
// or
import express = require("express"); // TypeScript-specific syntaxAfter changing tsconfig.json, restart your TypeScript server.
Verify if the package uses ES modules or CommonJS:
// package.json indicating ES modules
{
"type": "module",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
}
}
// package.json indicating CommonJS (default)
{
"main": "./dist/index.js"
}For ES module packages ("type": "module"), ensure your tsconfig.json uses appropriate settings:
{
"compilerOptions": {
"module": "node16",
"moduleResolution": "node16"
}
}For mixed packages, you might need to use dynamic imports or different import syntax.
For CommonJS modules without default exports, use one of these patterns:
// Pattern 1: Namespace import (works with esModuleInterop: false)
import * as fs from "fs";
fs.readFileSync("./file.txt");
// Pattern 2: Require syntax (TypeScript-specific)
import fs = require("fs");
// Pattern 3: Destructured require (for specific exports)
const { readFileSync } = require("fs");
// Pattern 4: With esModuleInterop: true, you can often use default import
import fs from "fs"; // Only works with esModuleInterop: true
// For modules that export a single function/class:
// If module has: module.exports = MyClass
import MyClass from "./MyClass"; // With esModuleInterop: trueCheck the module's actual export structure to choose the right pattern.
If you're using a JavaScript module without proper types, create a declaration file:
// types/my-module.d.ts
declare module "my-module" {
// If module has default export
export default function myFunction(): void;
// If module has named exports
export function helper(): string;
export const version: string;
// If module uses CommonJS export
export = myFunction;
// or for object exports
namespace myModule {
export function doSomething(): void;
}
export = myModule;
}Ensure the declaration matches the actual module structure. Test by checking what require("my-module") returns in Node.js.
### Understanding Module Export Patterns
TypeScript supports several export patterns:
1. ES Module Default Export:
// Export
export default function myFunction() { /* ... */ }
// or
export default class MyClass { /* ... */ }
// Import
import myFunction from "./module";2. ES Module Named Exports:
// Export
export function func1() { /* ... */ }
export const CONSTANT = "value";
// Import
import { func1, CONSTANT } from "./module";3. CommonJS module.exports:
// Export
module.exports = myFunction;
// or
module.exports = { func1, func2 };
// Import (with esModuleInterop: true)
import myFunction from "./module";
// or
import * as module from "./module";4. TypeScript export = (for CommonJS compatibility):
// Export
function myFunction() { /* ... */ }
export = myFunction;
// Import (TypeScript-specific)
import myFunction = require("./module");### esModuleInterop and allowSyntheticDefaultImports
- esModuleInterop: Changes runtime behavior to allow default imports from CommonJS modules. Adds helper code to check for .default property.
- allowSyntheticDefaultImports: Only affects type checking, not runtime. Allows you to write import React from "react" even if types say there's no default export.
For modern projects, set both to true in tsconfig.json.
### Module Resolution with Node16/NodeNext
With "moduleResolution": "node16" or "nodeNext":
// Must include .js extension for relative imports
import { helper } from "./utils/helper.js"; // Even if source is helper.ts
// For package imports, extension is not needed
import lodash from "lodash";This matches Node.js's actual ES module resolution.
### Checking Module's Exports
Use these techniques to inspect a module:
# Check JavaScript module's exports
node -e "console.log(Object.keys(require('module-name')))"
# For ES modules, check package.json exports field
cat node_modules/module-name/package.json | grep -A 10 '"exports"'
# Use TypeScript compiler to see resolved types
npx tsc --noEmit --traceResolution### Dynamic Imports as Alternative
When unsure about export structure, use dynamic imports:
// Runtime check of available exports
import("module-name").then(module => {
if (module.default) {
// Has default export
const func = module.default;
} else {
// Only named exports
const { namedExport } = module;
}
});This avoids compile-time errors but adds runtime complexity.
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