TypeScript export vs default export: разбираемся раз и навсегда
Привет, друг! Если ты только начинаешь свой путь в TypeScript (или уже не новичок, но всё ещё путаешься в экспортах), то эта статья — твой спасательный круг. Тема "TypeScript export vs default export" — одна из самых горячих на Stack Overflow, и не зря. Кажется, что мелочь, а сколько копий сломано! Давай разложим по полочкам, что к чему, и навсегда запомним, когда использовать export, а когда export default.
Мы не будем сухо перечислять правила. Мы разберём живые примеры, типичные ошибки новичков и дадим конкретные рекомендации. Погнали!
Что такое экспорт в TypeScript и зачем он нужен?
Представь, что ты пишешь большую программу. Ты же не будешь весь код пихать в один файл? Конечно, нет. Ты разбиваешь его на модули: один файл отвечает за работу с пользователями, другой — за расчёты, третий — за интерфейс. Экспорт — это способ сказать TypeScript: "Эй, эту функцию, класс или переменную можно использовать в других файлах". А импорт — это способ сказать: "Дай-ка я возьму эту штуку из другого файла".
В TypeScript есть два основных вида экспорта: именованный (named export) и экспорт по умолчанию (default export). И вот тут начинается самое интересное.
Именованный экспорт (named export) — точность и порядок
Именованный экспорт — это когда ты явно указываешь имя того, что экспортируешь. Это как если бы ты повесил на каждую коробку в своём гараже яркую бирку: "Инструменты", "Спортинвентарь", "Старые учебники".
Синтаксис очень простой. Просто добавь ключевое слово export перед объявлением:
Пример именованного экспорта
// utils.ts
export const PI = 3.14159;
export function calculateArea(radius: number): number {
return PI * radius * radius;
}
export class Circle {
constructor(public radius: number) {}
}
А теперь импортируем это в другой файл:
// app.ts
import { PI, calculateArea, Circle } from './utils';
console.log(PI); // 3.14159
const area = calculateArea(5);
const myCircle = new Circle(10);
Обрати внимание на фигурные скобки { } при импорте. Они — верный признак именованного экспорта. Ты можешь импортировать только то, что тебе нужно, и при этом ты обязан использовать те же имена, которые указаны при экспорте (ну, или переименовать их с помощью as, но об этом позже).
Плюсы именованного экспорта
- Явность: Ты всегда видишь, что именно экспортируется из модуля.
- Автодополнение: IDE (например, VS Code) отлично подсказывает имена при импорте.
- Рефакторинг: Если ты переименуешь экспортированную функцию, IDE переименует её во всех местах импорта. Это безопасно.
- Tree-shaking: Сборщики (Webpack, Vite) могут "вытрясти" неиспользуемый код, уменьшая размер итогового бандла.
Экспорт по умолчанию (default export) — удобство и лаконичность
Экспорт по умолчанию — это когда ты говоришь: "В этом файле есть одна главная сущность, и я хочу, чтобы её было удобно импортировать". Это как если бы ты сказал: "Вот моя визитка, на ней всё основное".
В каждом модуле может быть только один экспорт по умолчанию. Синтаксис:
Пример дефолтного экспорта
// logger.ts
const log = (message: string): void => {
console.log(`[LOG]: ${message}`);
};
export default log;
Или можно сразу объявить:
export default function log(message: string): void {
console.log(`[LOG]: ${message}`);
}
Импорт выглядит так (без фигурных скобок!):
// main.ts
import myLog from './logger';
myLog('Hello, world!'); // [LOG]: Hello, world!
Обрати внимание: при импорте мы можем назвать импортируемую штуку как угодно. myLog, logger, logFunction — всё сработает. Это удобно, но может привести к путанице.
Плюсы дефолтного экспорта
- Лаконичность: Не нужно запоминать точное имя. Импорт короче.
- Удобно для главной сущности модуля: Например, компонент React или главная функция библиотеки.
Главные отличия и когда что использовать
Теперь, когда мы разобрали оба подхода, давай сравним их в таблице (мысленно, конечно, но я всё распишу).
1. Количество экспортов
- Именованный: Сколько угодно. Хоть 50 функций и 100 констант.
- Дефолтный: Только один на модуль.
2. Имя при импорте
- Именованный: Должно совпадать с именем при экспорте (или использовать
as). - Дефолтный: Может быть любым. Это и плюс, и минус.
3. Автодополнение в IDE
- Именованный: Отличное автодополнение. IDE подскажет, что можно импортировать.
- Дефолтный: Автодополнение хуже. IDE часто не знает, как называется дефолтный экспорт, пока ты его не импортируешь.
4. Рефакторинг (переименование)
- Именованный: Безопасный рефакторинг. Все импорты обновятся автоматически.
- Дефолтный: При переименовании экспортируемой сущности импорты не обновятся, так как они используют произвольные имена.
Типичные ошибки новичков (и как их избежать)
Я видел это сотни раз. Давай разберём самые частые грабли.
Ошибка 1: Путаница с синтаксисом импорта
Самая популярная ошибка — попытка импортировать default экспорт в фигурных скобках или наоборот.
// Неправильно!
import { log } from './logger'; // Ошибка! log - это default export, нужны фигурные скобки? Нет!
//