Очистка операторов импорта TypeScript с помощью псевдонимов путей

Операторы импорта  —  это первые фрагменты кода, которые мы видим при открытии файла. Помимо логики, согласно которой использование кода до импорта приводит к ошибке во время выполнения, наличие этих операторов в начале помогает получить представление о том, какие фрагменты кода используются в конкретном файле.

В программной инженерии лучшие кодовые базы  —  это те, которые можно читать. Очень важно, чтобы разработчик писал лаконичный и чистый код. Усилия, направленные на повышение читабельности кода, приносят пользу в долгосрочной перспективе. Это приводит к уменьшению количества рефакторингов и ускоряет время выполнения работ по обслуживанию.

Использование псевдонимов путей

Мы можем применять псевдонимы путей, чтобы сделать операторы импорта намного чище. Это особенно полезно, когда необходимо импортировать код в глубоко вложенные компоненты. Вместо повторяющегося шаблона “возврат к родителю” (../), за которым следует сам путь к файлу, мы используем формат с префиксом, за которым следует путь к файлу. Сравнение этих двух методов показано ниже.

Без псевдонимов путей:

//файл HomeContainer.tsx
import { DictionaryService } from '../../application/services/dictionary.service';
import { ButtonPanel } from '../components/ButtonPanel';

С использованием псевдонимов путей (обратите внимание: @application/ и @presentation/  —  это псевдонимы, а services/random.service и container/random-container  —  пути, относящиеся к псевдонимам):

//файл HomeContainer.tsx
import { DictionaryService } from '@application/services/dictionary.service';
import { ButtonPanel } from '@presentation/components/ButtonPanel';

Совет: при выборе псевдонима рекомендуется называть его в честь родительской директории, которая позволяет группировать компоненты по принципу разделения задач (например, Model/View/Controller), или же  —  в чистой архитектуре  —  по их слоям. Это также поможет легко найти нужный файл в дереве каталогов даже без использования сочетания клавиш control/command + клик.

Примечание: использование символа @, как и в нашем примере, зависит от предпочтительного соглашения об именовании. Совершенно нормально вместо @application выбрать application. Опять же, соглашение об именовании зависит от стандартов, принятых среди членов команды или организации.

Пример каталога проекта

Ниже приведен каталог проекта, который мы будем использовать. Допустим, мы создаем очень простое приложение для работы со словарями. Для простоты у нас будет всего 3 основных компонента: (1) dictionary.service.ts, в котором должны содержаться сценарии использования; (2) HomeContainer.tsx, где находится компонент ButtonPanel, импортированный из (3) ButtonPanel.tsx. Конечно, у нас есть и файлы tsconfig.json и babel.config.js, которые обычно генерируются автоматически.

Что имеется в наличии?

Использование псевдонимов для типов позволяет изменить следующие файлы в проекте, расположенные в корневой папке.

  1. tsconfig.json  —  этот файл содержит спецификации требуемого поведения транскомпилятора.
  2. babel.config.js (если применимо; обычно для проектов React)  —  некоторые библиотеки используют Babel для транскомпиляции кода, использующего сложные синтаксические сахара, в код, понятный большинству браузеров. Возьмем, к примеру, React: Babel преобразует tsx или jsx в обычный код JavaScript.

Применим изменения

Сначала найдем файл tsconfig.json. Как уже говорилось, обычно он находится в корневой папке. Файл json должен выглядеть примерно так, как показано ниже. Мы будем изменять свойство compilerOptions.

{
  "compilerOptions": {
    "target": "es5",
  },
}

Добавим два вложенных свойства или подсвойства в compilerOptions.

Первое  —  свойство baseUrl, которое принимает строковое значение предполагаемого каталога baseUrl. Обычно мы устанавливаем его в ‘.’, что обозначает текущий каталог, где находится файл tsconfig.json, который является корнем или папкой MyProject. Ключевым моментом здесь является то, что мы устанавливаем baseUrl в корень, чтобы получить доступ к его подкаталогам, таким как папка src.

Далее добавим свойство paths, которое принимает объект с парой “ключ-значение” самого псевдонима и массив относительных путей к baseUrl, куда указывает псевдоним. Ключ  —  это строка, например “@application/*”. Она обозначает псевдоним. Значение, например [“src/application”],  —  это массив, содержащий путь, на который будет вести указание при добавлении нами префикса с псевдонимом @application.

Файл tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "baseUrl": ".",
    "paths": {
      "@application/*": ["src/application/*"],
      "@presentation/*": ["src/presentation/*"],
    }
  },
  "extends": "expo/tsconfig.base"
}

Звездочки, которые вы видите, называются подстановочными символами (wildcards). Эти звездочки обозначаются как любая последовательность символов. Возьмем для примера “@application/*” [“src/application/*”]. “@application/*” означает, что компилятор ищет операторы импорта, содержащие последовательность символов @application/, за которой следует ЛЮБАЯ другая последовательность символов (что-то вроде префикса).

В случае с [“src/application/*”] звездочка играет несколько иную роль. На этот раз она означает, что любой каталог является вложенным. Например, в папке presentation есть подкаталоги, такие как components и containers. Звездочка указывает компилятору включить эти подкаталоги и их содержимое в область видимости.

Файл babel.config.js (если применимо)

Если вы работаете над проектами, в которых задействованы библиотеки, использующие сложный синтаксис JavaScript или синтаксический сахар (например, React), в состав зависимостей будет входить Babel. В этом случае в корневом каталоге создастся файл babel.config.js.

Нам придется внести изменения в этот файл, чтобы разрешить импортировать псевдонимы. Изначально он должен выглядеть примерно так, как показано на фрагменте кода ниже:

module.exports = function (api) {
  api.cache(true);
  return {
    presets: [],
    plugins: [],
  };
};

Мы будем изменять свойство plugins, добавляя два аргумента. Но сначала нужно установить библиотеку под названием babel-plugin-module-resolver. Для этого выполним в терминале команду npm i babel-plugin-module-resolver. После установки можем внести изменения в файл babel.config.js.

Сначала добавим строку “module-resolver”, затем  —  объект со свойством alias. Аналогично изменениям, внесенным в файл tsconfig, добавляем пару “ключ-значение”, но на этот раз вместо массива значений свойство принимает только строку.

module.exports = function (api) {
  api.cache(true);
  return {
    presets: [],
    plugins: [
    [
    "module-resolver",
    {
      alias: {
        '@application': "./src/application",
        '@presentation': "./src/presentation",
      },
    },
    ],
    ],
  };
};

Также стоит отметить, что мы не будем использовать подстановочные символы в отличие от изменений в файле tsconfig.json. Для обозначения псевдонима мы просто указываем имя или префикс. Что касается пути, мы просто указываем каталог, относящийся к корню, на который должен указывать псевдоним. Это автоматически включит все подкаталоги и содержимое, и не нужно будет использовать символ звездочки.

Теперь можем заменить операторы импорта на псевдонимы, как я уже показывал ранее (см. раздел “Использование псевдонимов путей”).

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Dom Segundo: Make Cleaner TypeScript Import Statements with Path Aliasing

Предыдущая статьяПодходы к созданию линейных графиков для iOS-приложений на базе фреймворка SwiftUI
Следующая статьяНавигация по ландшафту ИИ в 2024 году: тренды, прогнозы, возможности. Часть 2