This TypeScript error occurs when you try to import a module using default import syntax (`import X from "./module"`) but the target module doesn't have a default export. The error indicates a mismatch between your import statement and the module's actual export structure.
The "Module has no default export" error is TypeScript's way of telling you that you're trying to import something that doesn't exist in the way you expect. In JavaScript/TypeScript modules, there are two main types of exports: named exports and default exports. When you use `import X from './module'`, you're asking for the module's default export. However, if the module only exports named exports (like `export const foo = 'bar'` or `export function baz() {}`) without a `export default` statement, TypeScript will throw this error. This is a common issue when: 1. Working with third-party libraries that changed their export structure 2. Refactoring your own code and forgetting to update imports 3. Mixing CommonJS and ES module syntax 4. Using TypeScript with `allowSyntheticDefaultImports` configuration issues
First, examine the module you're trying to import from to see what it actually exports.
// If the module looks like this (named exports):
export const myFunction = () => {};
export const MY_CONSTANT = 'value';
// You need to import like this:
import { myFunction, MY_CONSTANT } from './module';
// Or import everything:
import * as module from './module';Open the module file and look for export default statements. If you don't see any, you need to use named imports.
If the module uses named exports, update your import statement to use curly braces:
// Before (causes error):
import myModule from './module';
// After (correct):
import { specificExport } from './module';
// or
import * as myModule from './module';If you're not sure what named exports are available, check the module's source code or documentation.
If you control the module and want to keep using default imports, add a default export:
// In the module file:
const mainFunction = () => { /* ... */ };
const helperFunction = () => { /* ... */ };
// Export named exports as usual
export { helperFunction };
// Add a default export
export default mainFunction;
// Now this import works:
import mainFunction from './module';
import { helperFunction } from './module';You can also re-export a named export as default:
export { mainFunction as default };If you're importing from a CommonJS module (like many Node.js packages), you may need to adjust your tsconfig.json:
{
"compilerOptions": {
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
}
}- esModuleInterop: Enables better interoperability between CommonJS and ES modules
- allowSyntheticDefaultImports: Allows default imports from modules without default exports (TypeScript will assume they exist)
With these settings, you can import CommonJS modules that use module.exports = ... with default import syntax.
For third-party libraries, check their documentation or changelog. Many libraries have switched from default to named exports:
// Old version (default export):
import React from 'react';
// New version (named export):
import { useState, useEffect } from 'react';
// Some libraries support both:
import React from 'react'; // default
import { useState } from 'react'; // namedCheck the library's documentation for the correct import syntax. Look for migration guides if you're updating versions.
For modules with complex export patterns or conditional exports, you might need alternative approaches:
// Dynamic import (async)
const module = await import('./module');
const { namedExport } = module;
// CommonJS require (if module uses module.exports)
const module = require('./module');
// or with TypeScript interop
import * as module from './module';
// Type assertion as last resort
import * as module from './module';
const defaultExport = (module as any).default;Note: Dynamic imports are asynchronous and return Promises.
## Understanding Module Systems
TypeScript supports multiple module systems:
1. ES Modules (ESM): Modern standard using import/export
2. CommonJS: Node.js traditional system using require()/module.exports
3. AMD/UMD: Older browser module systems
## Common Pitfalls
1. Mixed module formats: Having some files as .js (CommonJS) and others as .mjs (ESM) can cause issues.
2. Dual package hazard: Some packages provide both ESM and CommonJS versions. TypeScript might pick the wrong one.
3. Export maps in package.json: Modern packages use "exports" field to control what's exported. Check the package's package.json for export maps.
4. Type declaration files (`.d.ts`): Sometimes the types are wrong. Check node_modules/@types/package-name/index.d.ts or the package's own type declarations.
## Debugging Tips
1. Use tsc --traceResolution to see how TypeScript resolves modules
2. Check node_modules/package-name/package.json for "main", "module", and "exports" fields
3. Look at the actual JavaScript file being imported (not just TypeScript declarations)
4. Use TypeScript Playground to test import/export scenarios
## Performance Considerations
- esModuleInterop adds helper code that can slightly increase bundle size
- Tree-shaking works better with named exports than default exports
- Consider using named exports exclusively for better code splitting
Type parameter 'X' is not used in the function signature
How to fix "Type parameter not used in function signature" in TypeScript
Type parameter 'X' is defined but never used
How to fix "Type parameter is defined but never used" in TypeScript
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