Module organization and resolution
Вопрос:
Какие ключевые различия между пространствами имен TypeScript и модулями ES6? Объясните, как стратегии разрешения (резолва) типов отличаются при использовании этих двух подходов для организации кода.
Подсказки:
- Учтите, как работает слияние деклараций при использовании пространств имен и модулей.
- Подумайте о области видимости и видимостях типов в обоих подходах.
- Отразите, как сборщики и разрешение модулей влияют на каждый подход.
Выше ожиданий:
- Директивы с тройными косыми чертами и модульное расширение
- Стратегии разрешения модулей (Классический против Node)
- Окружающие декларации модулей с шаблонами подстановок
Ответ:
Модули ES6 и namespaces (пространства имён) представляют два различных подхода к организации и инкапсуляции кода в TypeScript, с различными характеристиками и областями применения.
Ключевые различия:
- Резолвинг и загрузка модулей:
- Модули ES6 работают с файловой системой, где каждый файл рассматривается как отдельный модуль.
- Namespaces обеспечивают логическую группировку внутри файлов с помощью ключевого слова
namespace
. - Модули ES6 поддерживают загрузку во время выполнения и tree-shaking, в то время как пространства имён в основном являются конструкциями времени компиляции (compile time).
// Пример модуля ES6
// math.ts
export const add = (a: number, b: number) => a + b;
// main.ts
import { add } from './math';
// Пример пространства имён
namespace Mathematics {
export const add = (a: number, b: number) => a + b;
}
- Поведение объединения объявлений (declaration merging):
- Namespaces поддерживают иерархическое объединение через несколько файлов.
- Модулям ES6 требуется явное расширение модулей для добавления функциональности к существующим модулям.
- Объявления модулей ambient могут быть объединены с обычными объявлениями модулей.
// Объединение объявлений в пространствах имён
namespace Validation {
export interface StringValidator { isValid(s: string): boolean; }
}
namespace Validation {
export class RegexValidator implements StringValidator {
isValid(s: string): boolean { return true; }
}
}
- Стратегия резолвинга типов:
Компилятор TypeScript использует различные стратегии для резолвинга:
- Classic: Использует директивы triple-slash и ambient-модули.
- Node: Следует правилам разрешения модулей Node.js.
- Разрешение модулей: Настраивается через
tsconfig.json
.
// Пример директивы triple-slash
/// <reference path="./types.d.ts" />
// Карта путей в tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@utils/*": ["src/utils/*"]
}
}
}
- Ambient-модули и определения типов:
- Позволяют объявлять формы модулей без реализации.
- Поддерживают объединение объявлений с фактическими реализациями модулей.
- Разрешают определения типов для внешних библиотек.
// Объявление ambient-модуля
declare module "my-library" {
export function helper(): void;
export interface Config {
option: string;
}
}
- Расширение модулей:
- Модули ES6 поддерживают расширение существующих модулей через объединение объявлений.
- Требует явного синтаксиса
declare module
. - Полезно для добавления новой функциональности в модули сторонних разработчиков.
// Расширение модуля
declare module "original-module" {
export interface ExistingInterface {
newProperty: string;
}
}
Рекомендации для TypeScript:
- Используйте модули ES6 для:
- Разработки нового кода;
- Лучшей поддержки tree-shaking;
- Более чёткого управления зависимостями;
- Лучшей поддержки инструментов.
- Используйте пространства имён для:
- Поддержания кода legacy;
- Сценариев глобального расширения;
- Организации внутренних модулей внутри одного файла.
- Настройка разрешения модулей:
- Установите
moduleResolution
вtsconfig.json
; - Используйте карту путей для чистых импортов;
- Воспользуйтесь ambient-модулями для определений типов.
Выбор между модулями ES6 и пространствами имён часто зависит от:
- Требований проекта;
- Возможностей системы сборки;
- Предпочтений команды;
- Необходимости совместимости с кодом legacy.
0