The default keyword in TypeScript has two jobs. export default marks the main value a module exports, and default: in a switch runs when no case matches. Here are both in two lines:
export default function salesTax(amount: number) { /* ... */ } // module
switch (state) { case "TX": return 2; default: return 5; } // switch
Every snippet below was compiled in strict mode with TypeScript 7.0.2 and Node.js v22.22.2; the output comes straight from those runs.
You’ll also see the errors you’re likely to hit and the related defaults: parameters, generic types and ?? fallbacks.
What does export default do in TypeScript?
A module can have one default export: the thing it’s mainly about. The importer picks any local name for it and skips the curly braces. It’s a reserved word (see my list of TypeScript keywords), so no variable can be named default.
Here’s a two-file project. salesTax.ts exports a function as its default plus a named constant:
export default function salesTax(amount: number, rate = 0.0825): number {
return Math.round(amount * rate * 100) / 100;
}
export const STATE = "TX";
main.ts imports the default under a different name, calcTax, and grabs STATE in braces on the same line:
import calcTax, { STATE } from "./salesTax.js";
const subtotal = 249.99;
const tax = calcTax(subtotal);
console.log(`${STATE} tax on $${subtotal.toFixed(2)}: $${tax.toFixed(2)}`);
console.log(`Total: $${(subtotal + tax).toFixed(2)}`);
Output:
TX tax on $249.99: $20.62
Total: $270.61

The folder’s package.json sets "type": "module", so --module nodenext treats both files as ES modules. That’s why the import says ./salesTax.js; without the extension, tsc stops with TS2835.
If an import still won’t resolve, my guide to fixing Cannot find module in TypeScript walks through the usual causes.
What can you export as default?
A function, a class, or any expression, like export default 0.0825. Use export { shipping as default } for something declared earlier. What you can’t write is export default const rate = 0.0825; tsc rejects it with TS1109: Expression expected.
Error TS2528: A module cannot have multiple default exports
You get one default per file, because the importer never names what it wants. Add a second and the compiler flags both:
export default function salesTax(amount: number): number {
return amount * 0.0825;
}
const shipping = (miles: number): number => miles * 0.5;
export default shipping;
Output:
default_two_exports.ts(1,25): error TS2528: A module cannot have multiple default exports.
default_two_exports.ts(6,16): error TS2528: A module cannot have multiple default exports.

Keep one default and turn the rest into named exports with export const. If you’re mixing modules with older namespace code, namespaces vs modules in TypeScript explains why modules are the better choice today.
Default export vs named export: which should you use?
| Default export | Named export | |
|---|---|---|
| Per module | One | As many as you like |
| Import syntax | import calcTax from "./salesTax.js" | import { STATE } from "./salesTax.js" |
| Name at import | Any name you choose | Must match, or rename with as |
| Good fit | A file with one class, component or function | Utility files with several helpers |
I lean toward named exports for helper files because the names stay consistent across a codebase. Default exports still fit one-thing files, like a React component or a class.
With import * as tax, the default shows up as tax.default. JSON imports also arrive as a default, as covered in importing a JSON file in TypeScript.
The default case in a TypeScript switch statement
Inside a switch, default is the catch-all. It runs only when no case matches, and it doesn’t have to be last:
function shippingZone(state: string): string {
switch (state) {
case "TX":
case "OK":
return "South Central - 2 days";
case "CA":
return "West - 4 days";
default:
return "Standard - 5 days";
}
}
for (const s of ["TX", "OK", "CA", "NY"]) {
console.log(s, "->", shippingZone(s));
}
function statusText(code: number): string {
let text: string;
switch (code) {
default: // first in the list, still runs last
text = "Unknown";
break;
case 200:
text = "OK";
break;
case 404:
text = "Not Found";
}
return text;
}
console.log(statusText(200), "|", statusText(404), "|", statusText(500));
Output:
TX -> South Central - 2 days
OK -> South Central - 2 days
CA -> West - 4 days
NY -> Standard - 5 days
OK | Not Found | Unknown
New York has no case, so it gets the standard zone. In statusText(), only 500 lands on the default that sits first.
End a default that isn’t last with break or return, or it falls through into the next case. More patterns are in TypeScript switch statements and using switch case with enums.
How do you make a switch exhaustive with default and never?
When you switch over a union type, you can make default prove that every member was handled. Assign the value to a variable typed never. Here I forgot "enterprise":
type Plan = "free" | "pro" | "team" | "enterprise";
function monthlyPrice(plan: Plan): number {
switch (plan) {
case "free":
return 0;
case "pro":
return 12;
case "team":
return 30;
default: {
const unhandled: never = plan;
throw new Error(`Unknown plan: ${unhandled}`);
}
}
}
Output:
default_never_check.ts(12,13): error TS2322: Type '"enterprise"' is not assignable to type 'never'.

Inside default, TypeScript narrows plan to whatever no case caught. When that’s nothing, the type is never and the line compiles; type narrowing in TypeScript covers how that works. Add the missing case and it builds again:
case "enterprise":
return 99;
The throw still guards against bad API data at runtime. For checks that don’t fit a switch, a custom type guard with the is keyword in TypeScript works well.
Other defaults in TypeScript: parameters, generics and ??
You may have landed here looking for default values. None of these use the default keyword, but you’ll use all three daily:
// 1. Default parameter values
function shippingLabel(city: string, state = "TX", rush = false): string {
return `${city}, ${state}${rush ? " (rush)" : ""}`;
}
console.log(shippingLabel("Austin"));
console.log(shippingLabel("Denver", "CO", true));
console.log(shippingLabel("Dallas", undefined, true));
// 2. Default generic type parameter
interface ApiResponse<T = string> {
status: number;
data: T;
}
const order: ApiResponse = { status: 200, data: "Order 1042 shipped" };
const stock: ApiResponse<number> = { status: 200, data: 37 };
console.log("data types:", typeof order.data, typeof stock.data);
// 3. Fallback values with ?? (and why not ||)
function tipPercent(saved: number | null | undefined): number {
return saved ?? 18;
}
console.log("??:", tipPercent(0), tipPercent(null), tipPercent(undefined));
const saved: number = 0;
console.log("||:", saved || 18);
Output:
Austin, TX
Denver, CO (rush)
Dallas, TX (rush)
data types: string number
??: 0 18 18
||: 18

ApiResponse falls back to string, and ?? keeps a tip of 0.A default parameter only kicks in for undefined, so passing undefined skips one argument. Under strict mode, passing null fails with TS2345. Compare that with optional function parameters in TypeScript, which leave the value undefined.
T = string gives a generic a fallback type when you don’t pass one; more examples are in TypeScript generic object types. And ?? only replaces null or undefined, while || also wipes out 0, as shown in nullish coalescing vs logical OR.
Every use of default in TypeScript at a glance
| Syntax | What it does | Common error |
|---|---|---|
export default x | Main export of a module | TS2528 when there are two |
import name from "./file.js" | Imports the default under any name | TS2835 without .js under nodenext |
default: in switch | Runs when no case matches | Fall-through without break |
const x: never = value in default | Exhaustiveness check | TS2322 names the missed case |
(state = "TX") | Default parameter value | TS2345 when passing null |
<T = string> | Default generic type | Wrong data type: TS2322 |
Default values and narrowing show up in plenty of other places, so these four guides are worth a look next:
- Set default values in TypeScript interfaces
- TypeScript enums explained
- The satisfies operator in TypeScript
- The non-null assertion operator in TypeScript
Frequently asked questions
What is the default keyword in TypeScript?
It marks a module’s main export (export default) and the fallback branch of a switch statement (default:).
Can a TypeScript file have more than one default export?
No. A second export default fails with TS2528: A module cannot have multiple default exports. Use named exports for everything else.
Does the default case have to be last in a switch?
No. It runs only when no case matches, wherever it appears. If it isn’t last, end it with break or return to stop fall-through.