export type
Re-exports or exports a binding for type use only, so the declaration never appears in emitted JavaScript.
export type { T };
export type { T, U as V } from "mod";
export type * from "mod";
export type * as ns from "mod";
export { value, type T } from "mod";- Added in TypeScript 3.8
Parameters
| Parameter | Type | Description |
|---|---|---|
$T | identifier | The local or re-exported declaration to expose for type positions only. |
$U as Voptional | rename clause | Renames the export, exactly as in a value export. |
$"mod"optional | string literal | Optional module specifier. With it the form is a re-export; without it, a local declaration is exported type-only. |
$type (inline modifier)optional | keyword | Marks a single specifier inside an ordinary export clause as type-only, letting one statement carry both values and types. |
Errors
Re-exporting a type without the modifier while `isolatedModules` is on raises "Re-exporting a type when 'isolatedModules' is enabled requires using 'export type'."
Changelog
- PHP 3.8`export type { ... }` introduced alongside `import type`.
- PHP 4.5Inline `type` modifiers on individual export specifiers added.
- PHP 5.0`export type *` and `export type * as ns` added, so a whole namespace can be re-exported type-only.
- PHP 5.0`verbatimModuleSyntax` makes the modifier load-bearing: an export without `type` is emitted verbatim, even if every name in it is a type.
export type is the mirror image of import type: the binding it creates is usable only where a type is expected, and the statement is erased from the emitted JavaScript.
When to reach for it
Almost always in a barrel file — an index.ts that re-exports a package's public surface. This is the one place where the compiler cannot help you without the keyword. In export { Config } from "./types.js", a single-file transpiler has no idea whether Config is an interface or a const, so it emits the re-export; at runtime the property does not exist and consumers get undefined or, under strict ESM, a link-time failure. isolatedModules turns this into a compile error precisely to force the modifier.
It is also the way to publish a type under a different name than it has internally, or to expose a type while keeping the implementation module private.
What trips people up
export type * from "./mod" re-exports only the types of a module, silently dropping its values — which is what you want for a types-only barrel and a nasty surprise if you meant to re-export everything. And export type { Foo } where Foo is a class exports the type but not the constructor, so consumers can annotate with it but not instantiate it.
Example
// types.ts
export interface Config { port: number; host: string }
export const DEFAULT_PORT = 8080;
// index.ts (barrel)
export type { Config } from "./types.js"; // erased entirely
export { DEFAULT_PORT } from "./types.js"; // real re-export
// app.ts
import type { Config } from "./index.js";
import { DEFAULT_PORT } from "./index.js";
const cfg: Config = { port: DEFAULT_PORT, host: "localhost" };
console.log(cfg);
// -> { port: 8080, host: "localhost" }When to use it
- Re-export interfaces from a package's index.ts without emitting a dead runtime re-export
- Publish a type under a public name while the implementation module stays internal
- Satisfy the isolatedModules re-export error when migrating a barrel file to esbuild or swc
- Expose a library's option types while keeping its factory functions unexported
Frequently asked questions
Why does TypeScript say re-exporting a type requires export type?
Because `isolatedModules` is enabled and the compiler cannot prove at single-file granularity that the name is a type. Change `export { Foo } from "./foo.js"` to `export type { Foo } from "./foo.js"`, or add the inline modifier: `export { bar, type Foo } from "./foo.js"`.
Does export type work for classes and enums?
Yes, but consumers get only the type side. An `export type { MyClass }` lets others write `let x: MyClass`, while `new MyClass()` fails because the constructor value was never exported. Export a class normally if callers need to instantiate it.
What is the difference between export type * and export *?
`export type *` re-exports only the type declarations of the target module and emits nothing; `export *` re-exports everything, values included, and produces a real runtime re-export. Using the type-only form on a mixed module silently hides its functions, classes and constants.
More examples
Renaming on the way out, and the inline modifier
The emitted index.js contains only `export { HttpClient } from "./internal/http-client.js"`. The inline `type` modifier lets the class and its renamed options interface travel in one statement, which keeps the barrel readable and still satisfies verbatimModuleSyntax.
// internal/http-client.ts
export interface HttpClientRequestOptions {
method: "GET" | "POST";
timeoutMs: number;
}
export class HttpClient {
constructor(private opts: HttpClientRequestOptions) {}
describe(): string { return `${this.opts.method} @${this.opts.timeoutMs}ms`; }
}
// index.ts — one statement carrying a value and a renamed type
export { HttpClient, type HttpClientRequestOptions as RequestOptions } from "./internal/http-client.js";
// app.ts
import { HttpClient, type RequestOptions } from "./index.js";
const opts: RequestOptions = { method: "GET", timeoutMs: 250 };
console.log(new HttpClient(opts).describe());
// -> "GET @250ms"export type * versus export *
`types-only.js` compiles to an empty module: `export type *` erased the whole statement. `Point` is still reachable through it for annotations, but `ORIGIN` is not exported at all, which is the error the commented import would produce. Reach for `export type *` only when you genuinely want a types-only entry point.
// shapes.ts
export interface Point { x: number; y: number }
export const ORIGIN: Point = { x: 0, y: 0 };
// types-only.ts
export type * from "./shapes.js"; // Point survives, ORIGIN does not
// everything.ts
export * from "./shapes.js"; // both survive
// app.ts
import type { Point } from "./types-only.js";
import { ORIGIN } from "./everything.js";
// tsc: Module './types-only.js' has no exported member 'ORIGIN'.
// import { ORIGIN as missing } from "./types-only.js";
const p: Point = { x: ORIGIN.x + 3, y: ORIGIN.y + 4 };
console.log(p);
// -> { x: 3, y: 4 }
Discussion