TypeScript: чем отличается export default от export и когда что использовать?
Ключевое различие: именованный экспорт vs экспорт по умолчанию
В TypeScript (и ES6) существует два основных способа экспорта:
- Именованный экспорт —
export const/function/class - Экспорт по умолчанию —
export default
Главное отличие — количество и способ импорта.
Именованный экспорт (named export)
Позволяет экспортировать множество сущностей из одного модуля. При импорте нужно обязательно использовать те же имена в фигурных скобках:
// math.ts
export const PI = 3.14;
export function sum(a: number, b: number): number {
return a + b;
}
export class Calculator { /* ... */ }
// app.ts
import { PI, sum, Calculator } from './math';
Особенности:
- Имя при импорте должно совпадать с именем экспорта
- Можно использовать
asдля переименования:import { sum as add } from './math' - Можно импортировать всё сразу:
import * as Math from './math'— тогда Math.PI, Math.sum и т.д.
Экспорт по умолчанию (default export)
Позволяет экспортировать одну главную сущность из модуля. При импорте можно дать любое имя:
// logger.ts
export default class Logger {
log(message: string): void {
console.log(message);
}
}
// app.ts
import MyLogger from './logger'; // имя может быть любым
// или
import Logger from './logger'; // обычно называют как в исходнике
Особенности:
- В модуле может быть только один
export default - Имя при импорте выбираете вы сами (это может привести к путанице)
- Не нужно использовать фигурные скобки
Когда что использовать? Best practices
Используйте именованный экспорт, когда:
- Модуль содержит несколько функций/классов/констант
- Вы хотите явно указать, что именно экспортируется
- Вы работаете в команде — именованные экспорты легче рефакторить и искать
- Пример: утилиты, хелперы, константы, типы
Используйте экспорт по умолчанию, когда:
- Модуль представляет одну главную сущность (один класс, одну функцию)
- Это компонент React (традиция, но не строгое правило)
- Пример:
export default class App,export default function App()
Практический пример: смешанный экспорт
Часто используют оба подхода в одном файле:
// user.ts
export default class User {
constructor(public name: string) {}
}
export function createUser(name: string): User {
return new User(name);
}
export const DEFAULT_USER = new User('Guest');
// app.ts
import User, { createUser, DEFAULT_USER } from './user';
Здесь User — главная сущность (экспорт по умолчанию), а createUser и DEFAULT_USER — дополнительные (именованные).
Рекомендация от TypeScript-сообщества
Многие разработчики (включая авторов популярных библиотек) склоняются к тому, чтобы избегать export default в пользу именованных экспортов. Причины:
- Лучшая поддержка автодополнения в IDE
- Проще рефакторинг (переименование)
- Единообразие кода
- Меньше путаницы с именами при импорте
Однако для React-компонентов и одного главного экспорта — default всё ещё широко используется.
Итог
Выбор между export и export default зависит от контекста. Для маленьких модулей с одной сущностью — default. Для библиотек, утилит и всего, где важна ясность — именованный экспорт. Можно комбинировать оба подхода в одном файле.
Альтернативный взгляд: всегда используйте именованные экспорты
Есть подход, который набирает популярность в TypeScript-сообществе: вообще отказаться от export default. Вот аргументы:
- Единообразие импорта — всегда используете фигурные скобки, нет путаницы с синтаксисом
- Лучшая поддержка рефакторинга — IDE может переименовать экспорт и все импорты сразу
- Tree shaking — сборщики (Webpack, Vite) лучше оптимизируют именованные экспорты
- Явность — вы всегда знаете, что импортируете, имя не может быть изменено случайно
Пример реализации:
// user.ts
export class User {
constructor(public name: string) {}
}
export function formatUser(user: User): string {
return `User: ${user.name}`;
}
// app.ts
import { User, formatUser } from './user';
Если нужно экспортировать "главную" сущность, просто называйте файл соответственно (например, user.ts экспортирует User). Это делает код более предсказуемым и упрощает работу в больших проектах.
Многие современные библиотеки (например, TypeScript сам, Lodash, RxJS) переходят на именованные экспорты. React — одно из немногих исключений, где default export остаётся стандартом де-факто.