The Problem ContextI recently migrated a mid-sized React codebase—roughly 45,000 lines of code—from Webpack to Vite. The transition was mostly seamless until I touched the 'barrel files.' These index.ts files aggregate our exports, but they caused the Vite dev server to throw a fit. The console immediately flagged this error:
Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'.
This happens because Vite uses esbuild for transpilation. Unlike the standard TypeScript compiler (tsc), which analyzes your entire project graph, esbuild processes each file in total isolation. It is incredibly fast—often 10x to 100x faster than tsc—but it has a blind spot. It cannot tell if an exported name is a JavaScript constant or a TypeScript interface that should be erased during the build.
The Debug ProcessThe root of the issue lies in your tsconfig.json. If you are using modern build tools, you likely have this setting enabled:
{
"compilerOptions": {
"isolatedModules": true
}
}
When isolatedModules is active, TypeScript prevents you from using patterns that a single-file transpiler can't handle. Re-exporting a type using standard syntax is one of those forbidden patterns. Take this common example in a src/types/index.ts file:
// src/types/user.ts
export interface User {
id: string;
name: string;
}
// src/types/index.ts
export { User } from './user'; // <-- This triggers the error
The transpiler sees export { User } and gets confused. It doesn't know whether to generate code for a runtime object or to delete the line entirely because User is just a type.
The Solutions### 1. Use explicit 'export type'The most straightforward fix is to tell the compiler exactly what you are doing. This syntax was introduced in TypeScript 3.8 and explicitly marks the export for erasure.
// Change this:
export { User } from './user';
// To this:
export type { User } from './user';
2. Mixed exports (TypeScript 4.5+)If you need to export a component and its corresponding type from the same file, you don't need two separate lines. Inline type modifiers make this much cleaner.
// src/components/index.ts
export {
Button,
type ButtonProps
} from './Button';
3. Separate imports and exportsFor teams stuck on older TypeScript versions or those who prefer a more verbose style, you can split the operation. Import the type first, then export it separately.
import { User } from './user';
export type { User };
VerificationDon't just rely on the Vite HMR (Hot Module Replacement) to tell you it's fixed. I always run a manual type check in the terminal to be certain:
npx tsc --noEmit
The --noEmit flag is perfect here. It performs a full type check without generating any .js files, which is exactly what you want when Vite or esbuild is handling the actual bundling.

