TypeScript / 38 минут
Модули, tsconfig и сборка
Настройте strict-проверку, модули, декларации и разделение типов и значений.
- Настройте strict-проверку, модули, декларации и разделение типов и значений.
- Применить тему в задаче «Модули, tsconfig и сборка» и объяснить граничные случаи.
Около 8 минут на чтение и разбор примеров. Практика — отдельно, в своём темпе.
Проверка и выпуск JavaScript — разные стадии
TypeScript-проект нуждается не только в .ts-файлах, но и в согласованной конфигурации проверки и запуска. Компилятор может проверять типы, преобразовывать синтаксис и генерировать JavaScript; сборщик иногда выполняет часть этих задач отдельно. Если инструмент только удаляет аннотации, это ещё не означает полноценного typecheck. В проекте должен быть явный обязательный шаг проверки.
Команда tsc --noEmit позволяет проверить код без выпуска файлов. В CI её удобно отделить от сборки приложения, чтобы ошибка типов не скрылась за успешной трансформацией. Конкретный фреймворк может предоставлять собственную команду, которая дополнительно учитывает компоненты и генерируемые типы. Главное — знать, какая проверка действительно запускается и с какой конфигурацией.
Базовые настройки strict
strict включает семейство более строгих проверок. Он помогает не забыть неявный any и отсутствие значения, но не делает внешний ввод проверенным автоматически. Опции noUncheckedIndexedAccess и exactOptionalPropertyTypes полезно рассматривать отдельно: не каждая строгая настройка входит в одно и то же семейство. Не включайте или отключайте параметры случайным набором без понимания их влияния на контракт.
{
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmitOnError": true
}
}Это пример для подходящего Node.js-проекта, а не универсальная конфигурация для любого сборщика или Nuxt. Фреймворк может генерировать базовый tsconfig и требовать его расширения. Нельзя бездумно заменить его отдельным минимальным файлом и ожидать сохранения всех путей, типов окружения и настроек компонентов.
target, lib и доступность API
target определяет выпуск определённых синтаксических конструкций, а lib участвует в описании доступных стандартных API. Они не устанавливают runtime-полифиллы автоматически. Успешная проверка вызова нового метода массива не гарантирует, что старый браузер реально содержит его реализацию. Целевую среду и стратегию совместимости нужно задавать отдельно.
const values: number[] = [3, 1, 2];
const sorted = values.toSorted((a, b) => a - b);Такой код требует соответствующего API у выполняющей среды или подходящего полифилла. Аналогично DOM-типы не создают настоящий document в Node.js. Разрешённые компилятором имена должны соответствовать месту запуска, а не просто присутствовать в широком наборе глобальных деклараций.
Формат модулей и import type
ESM и CommonJS имеют разные способы загрузки и экспорта. TypeScript должен согласовать module и moduleResolution с реальной средой или сборщиком. Поле type в package.json, расширения файлов и правила specifier влияют на то, какой код получится и как он будет выполняться. Настройка path alias не всегда переписывает runtime-путь сама по себе.
import { posix } from 'node:path';
import type { Stats } from 'node:fs';
const filename = posix.basename('/courses/intro.ts');
type FileInfo = Pick<Stats, 'size'>;posix нужен как реальное значение, а Stats используется только для типа. import type явно отделяет второй случай и не должен применяться к функции, которую вы собираетесь вызвать. Различие особенно важно при настройках сохранения синтаксиса модулей и при работе с зависимостями, имеющими побочные эффекты загрузки.
Декларации и границы зависимостей
.d.ts описывает API существующего JavaScript, но не содержит его реализацию для запуска. Пакет может поставлять декларации сам или получать их из @types. Если типы не соответствуют установленной runtime-версии, автодополнение может обещать несуществующий метод. Фиксируйте зависимости lockfile и проверяйте совместимость версий, а не ориентируйтесь только на найденный пример.
declare function formatTitle(value: string): string;
// Декларация сообщает тип, но не создаёт runtime-функцию.skipLibCheck может уменьшить стоимость проверки деклараций зависимостей, но не заменяет проверку собственного кода и не доказывает совместимость всех библиотек. Аналогично suppress-утверждения и @ts-ignore следует использовать только с понятной локальной причиной и планом проверки, а не как универсальное решение любой ошибки сборки.
Практика и итоговый TypeScript-проект
Задание использует обычный import значения posix и типизированный массив путей. Решение компилируется в строгом режиме внутри песочницы. Вы должны вернуть basename каждого пути, сохранив порядок и пустой массив. Это проверяет связь аннотаций, модульного импорта и реального выполнения, а не только красивую сигнатуру.
Итоговый проект курса — типизированный API-клиент. Разделите транспортный запрос, проверку unknown, модель результата и отображение ошибки. Добавьте отмену устаревшего запроса, тест повреждённого ответа и обязательный typecheck. Готовность проекта означает согласованность статических контрактов с runtime-поведением, а не отсутствие красных подчёркиваний в одном открытом файле редактора.