Хотите заказать веб-сайт? Связаться с нами

TypeScript в деле — компилятор, проверка и строгий режим

В прошлом уроке мы разобрались, зачем нужен TypeScript, и установили его. Сегодня мы перейдём к практике и разберёмся, что же на самом деле представляет собой этот инструмент. Многие новички думают, что TypeScript — это просто «JavaScript с типами». На самом деле это гораздо больше. TypeScript — это целая экосистема, которая включает в себя:

  1. Язык программирования (синтаксис с типами, который мы начали изучать).
  2. Мощный type checker — программу, которая анализирует ваш код и ищет потенциальные ошибки ещё до выполнения.
  3. Сборщик (компилятор) — который превращает ваш .ts код в обычный .js, понятный браузерам и Node.js.

Улучшатель IDE — вы уже могли заметить, что в редакторе кода (особенно в VS Code) появляются подсказки, автодополнение и предупреждения. Это заслуга TypeScript, который работает под капотом даже с обычными JavaScript файлами!

Сегодня мы научимся пользоваться этими возможностями по-настоящему. И начнем с неожиданного факта.

TypeScript в деле — компилятор, проверка и строгий режим

Проверка JavaScript файлов (JSDoc и не только)

Самое крутое в TypeScript — для того, чтобы начать получать пользу, вам не нужно сразу переписывать весь проект на TypeScript. Компилятор tsc умеет проверять обычные .js файлы, если указать ему специальный флаг.

Представьте, что у вас есть старый JavaScript проект, где вы не хотите ничего ломать. Вы можете просто запустить TypeScript в режиме проверки, и он найдёт скрытые проблемы, о которых вы даже не догадывались.

Создадим файл old-project.js со следующим содержимым (без единой строчки TypeScript):

// old-project.js
function greetUser(user) {
  return "Hello, " + user.name;
}

const user = { name: "Alice" };
const admin = null;

console.log(greetUser(user)); // 'Hello, Alice'
console.log(greetUser(admin)); // Ошибка, но мы её не видим, пока не запустим

Чтобы проверить этот файл на наличие скрытых проблем, мы можем использовать TypeScript в режиме проверки JavaScript. Запустим компилятор с флагом --allowJs (разрешить входные файлы .js) и --checkJs (проверять их типы):

tsc --allowJs --checkJs --noEmit old-project.js

Разберём флаги:

  1. --allowJs — разрешает компилятору читать .js файлы.
  2. --checkJs — включает проверку типов внутри этих файлов (без этого флага он просто скопирует файлы как есть).
  3. --noEmit — говорит компилятору: «Не создавай выходные файлы (.js), просто проверь код».

В результате вы увидите ошибку:

old-project.js:10:23 - error TS2345: Argument of type 'null' is not assignable to parameter of type '{ name: string; }'.

Обратите внимание: мы не написали ни одного типа, но компилятор понял, что функция greetUser ожидает объект со свойством name (потому что мы передали туда объект user). Когда мы попытались передать null, TypeScript нас предупредил. Это называется выводом типов (type inference), и это очень мощный механизм.

Запуск компилятора в реальном проекте

Ручной ввод длинных команд быстро надоедает. В реальной разработке мы создаём файл конфигурации tsconfig.json, в котором прописываем все настройки раз и навсегда.

Создайте папку проекта и выполните инициализацию:

tsc --init

Эта команда создаст файл tsconfig.json с кучей настроек. Среди них есть два самых важных параметра:

  1. target — в какую версию JavaScript компилировать (например, ES2020).
  2. strict — главный переключатель, который включает все строгие проверки.

Сегодня мы сосредоточимся на флаге strict. Найдите его в вашем tsconfig.json и убедитесь, что он установлен в true:

{
  "compilerOptions": {
    "strict": true
  }
}

Что даёт strict: true? Он включает целый набор правил, которые заставят вас писать надёжный код. Среди них:

  1. noImplicitAny — запрещает неявный тип any. Если TypeScript не может вывести тип, вы обязаны указать его явно.
  2. strictNullChecks — запрещает присваивать null или undefined туда, где ожидается обычное значение (если вы явно это не разрешили).
  3. strictFunctionTypes — более строгая проверка функций.

Практическое задание: ловим ошибки

Теперь я предлагаю вам попрактиковаться. Я подготовил JavaScript код с несколькими скрытыми ошибками. Ваша задача — скопировать его в файл practice.ts и запустить компилятор с strict: true.

Вот наш подопытный:

// practice.ts
function calculateDiscount(price, discountPercent) {
  return price * (discountPercent / 100);
}

const items = [
  { name: "Laptop", price: 1000 },
  { name: "Mouse", price: 50 },
  { name: "Keyboard" } // Ой! Забыли указать цену
];

function applyDiscounts(cart) {
  for (let i = 0; i <= cart.length; i++) {
    const item = cart[i];
    const discounted = calculateDiscount(item.price, 10);
    console.log(`${item.name} discounted price: $${discounted}`);
  }
}

applyDiscounts(items);

Запустите компилятор командой tsc или tsc practice.ts. Вы увидите несколько ошибок. Я рекомендую не читать дальше, пока вы не попытаетесь их исправить самостоятельно.

Разбор решения

Давайте разберем, что нашёл компилятор и как это чинить.

Ошибка 1: Неявный any

Parameter 'price' implicitly has an 'any' type.
Parameter 'discountPercent' implicitly has an 'any' type.

TypeScript ругается, что мы не указали типы у параметров функции calculateDiscount. В строгом режиме это запрещено.

Исправление: добавим типы явно.

function calculateDiscount(price: number, discountPercent: number): number {
  return price * (discountPercent / 100);
}

Ошибка 2: price может быть undefined

Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
  Type 'undefined' is not assignable to type 'number'.

В массиве items у объекта Keyboard нет поля price. TypeScript вывел, что item.price — это number | undefined (число или неопределённость), а функция calculateDiscount принимает только чистое число.

Исправление: Добавим проверку или укажем цену по умолчанию (на практике лучше добавить отсутствующее поле, но для демонстрации используем защитный if).

function applyDiscounts(cart: any[]) {
  for (let i = 0; i < cart.length; i++) {
    const item = cart[i];
    if (item.price !== undefined) {
      const discounted = calculateDiscount(item.price, 10);
      console.log(`${item.name} discounted price: $${discounted}`);
    } else {
      console.log(`${item.name} has no price!`);
    }
  }
}

Ошибка 3: Выход за пределы массива

Index signature in type 'any[]' only permits reading. // Или ошибка доступа, но главное — логическая ошибка

Посмотрите на условие в цикле: i <= cart.length. Когда i равен длине массива (например, 3 при длине 3), элемент cart[3] равен undefined. В старой JS версии это бы просто упало или дало NaN. Но TypeScript ещё на этапе написания подсказывает вам, что это подозрительный код, если вы включите проверку индексов (она тоже входит в strict).

Исправление: Меняем <= на <.

for (let i = 0; i < cart.length; i++) {
  // ...
}

Итоговый рабочий код:

function calculateDiscount(price: number, discountPercent: number): number {
  return price * (discountPercent / 100);
}

const items: { name: string; price?: number }[] = [
  { name: "Laptop", price: 1000 },
  { name: "Mouse", price: 50 },
  { name: "Keyboard" }
];

function applyDiscounts(cart: { name: string; price?: number }[]) {
  for (let i = 0; i < cart.length; i++) {
    const item = cart[i];
    if (item.price !== undefined) {
      const discounted = calculateDiscount(item.price, 10);
      console.log(`${item.name} discounted price: $${discounted}`);
    } else {
      console.log(`${item.name} has no price!`);
    }
  }
}

applyDiscounts(items);
Из ноутбука появляются летающие светящиеся экраны

Оживи свой сайт. Освой JavaScript!

Статичная верстка — это только скелет. Наш онлайн-курс "JavaScript с нуля до профи" даст твоим страницам мышцы и нервы. Научись создавать слайдеры, формы, интерактивные карты и получать данные с сервера.

От теории — к реальным скриптам в твоём портфолио.

Подробнее о курсе

Итог урока

Сегодня мы на практике увидели, что TypeScript — это не просто синтаксис, а целый набор инструментов:

Он может проверять даже обычный JavaScript (с флагами --allowJs и --checkJs).

Файл tsconfig.json с опцией "strict": true — ваш лучший друг. Он находит проблемы, которые вы могли бы не заметить годами.

Компилятор не даёт вам выстрелить себе в ногу, заставляя явно указывать типы и обрабатывать потенциально опасные места (вроде null и undefined).

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

В следующем уроке мы начнём погружаться в синтаксис типов, разберём примитивы, массивы, кортежи и, самое главное, Union Types — объединения, которые позволяют нам быть гибкими, но безопасными.

Теги: