Перейти к содержанию

Проблемы с export default

Предположим, у вас есть файл foo.ts со следующим содержимым:

1
2
class Foo {}
export default Foo;

Вы должны импортировать его (в bar.ts), используя синтаксис ES6, как показано ниже:

1
import Foo from './foo';

Здесь есть несколько проблем с удобством сопровождения:

  • Если вы переименуете Foo в foo.ts, он не переименуется его в bar.ts.
  • Если вам в конечном итоге потребуется экспортировать больше сущностей из foo.ts (что довольно распространенная ситуация), вам придется переделать синтаксис импорта.

По этой причине я рекомендую простой экспорт + деструктурированный импорт. Например foo.ts:

1
export class Foo {}

А затем:

1
import { Foo } from './foo';

Ниже я также привожу еще несколько причин.

Плохая обнаруживаемость

У экспорта по умолчанию очень низкая обнаруживаемость. Вы не можете исследовать модуль с помощью intellisense, чтобы узнать, есть ли у него экспорт по умолчанию или нет.

При экспорте по умолчанию вы ничего здесь не получите (может быть модуль экспортирует что-то по умолчанию / а может и нет ¯\_(ツ)_/¯):

1
import /* здесь */ from 'something';

Без экспорта по умолчанию вы получите хорошее автодополнение intellisense:

1
import /* здесь */ 'something';

Автодополнение

Независимо от того, знаете вы об экспорте или нет, вы можете автодополнить импорт import {/*здесь*/} from "./foo";. Это упрощает работу разработчиков.

Несочетаемость с CommonJS

Использование default ужасные испытания для commonJS пользователей, которым приходится использовать const {default} = require('module/foo'); вместо const {Foo} = require('module/foo'). Скорее всего, при импорте вы захотите переименовать экспорт по умолчанию во что-нибудь другое.

Защита от опечаток

Вы не получите опечаток, например, когда один разработчик пишет import Foo from "./foo";, а другой пишет import foo from "./foo";

Автоимпорт в TypeScript

Автоматический импорт лучше всего работает c именованным экспортом. Вы используете Foo, и автоматический импорт запишет import { Foo } from "./foo"; потому что это четко определенное имя, экспортированное из модуля. Некоторые инструменты будут пытаться волшебным образом прочитать и логически вывести имя и для экспорта по умолчанию, но такая магия уже не так надежна.

Реэкспорт

Реэкспорт является обычным явлением для корневого файла index в пакетах npm и заставляет вас вручную указать экспорт по умолчанию, например export { default as Foo } from "./foo"; (экспорт по умолчанию) по сравнению с export * from "./foo" (именованный экспорт).

Динамический импорт

Экспорт по умолчанию раскрывается с дополнительным default при динамическом импорте, например:

1
2
const HighCharts = await import('https://code.highcharts.com/js/es-modules/masters/highcharts.src.js');
HighCharts.default.chart('container', { ... }); // Обратите внимание `.default`

Лучше с именованным экспортом:

1
2
const {HighCharts} = await import('https://code.highcharts.com/js/es-modules/masters/highcharts.src.js');
HighCharts.chart('container', { ... }); // Обратите внимание `.default`

Требуется две строки для не-классов / не-функций

Достаточно одной инструкции для функции/класса, например:

1
export default function foo() {}

Достаточно одной инструкции для безымянных / типизированых объектов, например:

1
2
3
4
export default {
    notAFunction: 'Да, я не функция или класс',
    soWhat: 'Экспорт сейчас *удален* из объявления',
};

Но в противном случае нужны две инструкции:

1
2
3
4
5
6
7
// Если вам нужна именованная константа (здесь `foo`) для локального
// использования ИЛИ нужно описать тип (здесь `Foo`)
const foo: Foo = {
    notAFunction: 'Да, я не функция или класс',
    soWhat: 'Экспорт сейчас *удален* из объявления',
};
export default foo;

Комментарии