Default Exports in TypeScript

Default exports let a TypeScript module export a single main value. Learn how they work, when to use them, and the tradeoffs compared to named exports.

6 min read

Default exports in TypeScript let a module expose one primary value as its main export. Unlike named exports, where the importer must use the exact exported name, a default export lets the importing file choose its own local name. Every module can have at most one default export.

Here is the simplest default export. The first file exports a function as its default, and the second imports it under a different local name:

typescripttypescript
// greet.ts
export default function greet(name: string): string {
  return `Hello, ${name}!`;
}

The importer can choose any name it likes because a default import has no name to check against. Here the original greet function becomes sayHello in the consuming file:

typescripttypescript
// app.ts
import sayHello from "./greet.js";
 
console.log(sayHello("TypeScript"));

The original function is called greet, but the importer names it sayHello. Both names work, because the compiled JavaScript does not preserve the original name as part of the module binding. Running this code prints Hello, TypeScript! to the console.

TypeScript checks that the default export exists and that its type signature matches how you use it, but it does not enforce that all importers use the same name. This flexibility is the defining tradeoff of default exports.

Default Export Syntax

TypeScript supports several ways to define a default export. Each has a different use case.

Inline default export is the most common pattern. Put export default directly before a function or class declaration.

typescripttypescript
// Calculator.ts
export default class Calculator {
  add(a: number, b: number): number {
    return a + b;
  }
 
  multiply(a: number, b: number): number {
    return a * b;
  }
}

Default export after declaration is useful when the name matters for internal references within the module. Declare first, then export separately.

typescripttypescript
// config.ts
const appConfig = {
  port: 3000,
  host: "localhost",
  debug: true,
};
 
export default appConfig;

Default export of a type has a syntax constraint: you cannot write export default interface. Instead, define the type first and export it separately, or use a type alias with the export default type form.

Typing a Default Export

When you export a function or class as default, TypeScript infers the type automatically. You can also add an explicit type annotation when the inferred type is not precise enough.

typescripttypescript
// formatter.ts
export default function format(
  value: number,
  locale: string = "en-US"
): string {
  return value.toLocaleString(locale);
}

For object defaults, TypeScript infers the shape, but you can make it explicit with a type annotation on the variable. An explicit type gives better autocomplete when consuming the default export and catches property typos in the object literal.

Re-Exporting a Default Export

You can re-export the default export from another module. There are two patterns for this.

Re-export a named export as the default of the current module. This forwards a named export from one module as the default export of another. First, a module with a named export:

typescripttypescript
// math.ts
export function add(a: number, b: number): number {
  return a + b;
}

Now a barrel file that re-exports that named function as its own default, so consumers can import it without curly braces:

typescripttypescript
// index.ts
export { add as default } from "./math.js";

Alternatively, pass through another module's default unchanged. Use export { default } from to re-export a default as a default.

typescripttypescript
// index.ts
export { default } from "./math.js";

This passes through the default export unchanged. Consumers of index.ts get the same default as if they had imported from math.ts directly. For more on this pattern, see barrel files in TypeScript.

Default Export with Named Exports

A module can have both a default export and named exports. This pattern is common in libraries that provide a main function plus configuration helpers.

typescripttypescript
// api.ts
interface RequestConfig {
  baseURL: string;
  timeout: number;
}
 
export const defaultConfig: RequestConfig = {
  baseURL: "https://api.example.com",
  timeout: 5000,
};
 
export default function api(path: string) {
  return fetch(`${defaultConfig.baseURL}${path}`);
}

Consumers can take just the default if that is all they need, or grab the named exports for advanced usage. The default import is the main function, and named imports like defaultConfig are secondary helpers.

Default Exports vs Named Exports

Each style has strengths. The choice depends on how your module is consumed.

ScenarioBetter choiceReason
Module exports one main thingDefault exportClear intent: this is the point of this module
Module exports several utilitiesNamed exportsEach utility is independently accessible
Refactoring across many filesNamed exportsRename refactoring works project-wide
Tree-shaking is criticalNamed exportsBundlers can eliminate unused named exports more reliably
Framework component fileDefault exportConvention in React, Vue, Svelte, and similar
Library public APINamed exportsConsumers get autocomplete and consistent names

Named exports give better tooling support because every import site uses the same name. Default exports give more flexibility because each importer can choose a name that fits its local context. For a deeper comparison, see named exports in TypeScript.

Common Mistakes

Forgetting the curly braces with named imports. If a module uses a default export and you try to import it with curly braces, TypeScript reports that the module has no named export with that name. Use import add from "./math.js" (no curly braces) for default exports.

Using different names for the same default export across files. Since TypeScript does not enforce consistent naming for default imports, you can end up with import api from './api.js' in one file and import client from './api.js' in another. This makes find-all-references less useful. Agree on a consistent name across the project.

Exporting a default that is too complex. If your default export is a large object with many unrelated properties, consider splitting it into named exports. A default export should represent one clear concept that stands on its own.

Trying to use export default interface inline. This syntax is not valid TypeScript. The compiler rejects it with a clear error. Define the interface first, then export it as default in a separate statement.

Rune AI

Rune AI

Key Insights

  • A default export is the primary export of a module, imported without curly braces.
  • The importing file chooses the local name. TypeScript does not enforce consistency across files.
  • Default exports can be functions, classes, objects, or values, and can include a type annotation.
  • Use export default for single-purpose modules like components or configuration objects.
  • Prefer named exports when a module shares multiple values or when tooling precision matters.
RunePowered by Rune AI

Frequently Asked Questions

Can a TypeScript module have both default and named exports?

Yes. A module can have one default export and any number of named exports. This pattern is common in libraries that want to provide a main entry point plus utility helpers.

Does the import name need to match the original function name for a default export?

No. The importer chooses the local name. If the source module exports default function add, the importer can write import sum from './math.js'. The name is arbitrary.

Can I export a type as the default export?

Yes, but not with inline syntax. You cannot write export default interface User. Define the type first and export it separately, or use a type alias with export default type.

Conclusion

Default exports are a concise way to share a single main value from a module. They work well for components, classes, and single-purpose modules. However, they trade tooling precision for import flexibility. For most TypeScript projects, prefer named exports for shared utilities and reserve default exports for modules with one clear primary export.