Полное руководство по TypeScript

Изучите TypeScript с нуля до продвинутого уровня, освоив статическую типизацию для создания надежных и масштабируемых JavaScript-приложений. Курс охватывает все ключевые аспекты языка, от базовых типов до сложных архитектурных решений.

1. Основы TypeScript: установка, настройка окружения и базовые типы данных

Основы TypeScript: установка, настройка окружения и базовые типы данных

Добро пожаловать в курс «Полное руководство по TypeScript». В этой первой статье мы заложим фундамент вашего понимания этого мощного языка. Мы разберем, как подготовить рабочее место, напишем первую программу и погрузимся в систему типов, которая делает TypeScript таким популярным инструментом в современной веб-разработке.

Что такое TypeScript и зачем он нужен?

TypeScript — это язык программирования, разработанный Microsoft. Часто его называют «надмножеством» (superset) JavaScript. Это означает, что любой валидный код на JavaScript также является валидным кодом на TypeScript. Однако TypeScript добавляет то, чего так не хватает в чистом JS — статическую типизацию.

!Визуализация отношения между языками: TypeScript включает в себя все возможности JavaScript и расширяет их.

Главное преимущество TypeScript заключается в том, что он позволяет находить ошибки еще на этапе написания кода, а не во время его выполнения в браузере пользователя. Это значительно повышает надежность приложений и упрощает поддержку больших проектов.

Установка и настройка окружения

Прежде чем писать код, нам необходимо установить инструменты. TypeScript не выполняется браузером напрямую; он должен быть скомпилирован (транслирован) в обычный JavaScript. Для этого нам понадобится компилятор.

Шаг 1: Установка Node.js

Для работы с инструментами TypeScript вам потребуется Node.js. Если он у вас еще не установлен, скачайте LTS-версию с официального сайта.

> Официальный сайт Node.js

Шаг 2: Установка компилятора TypeScript

После установки Node.js откройте терминал (командную строку) и выполните следующую команду для глобальной установки TypeScript:

Эта команда использует пакетный менеджер npm для скачивания и установки компилятора tsc (TypeScript Compiler) в вашу систему.

Чтобы проверить, что установка прошла успешно, введите:

Вы должны увидеть номер установленной версии, например, Version 5.3.3.

Шаг 3: Настройка проекта

Создайте новую папку для вашего проекта и откройте её в терминале. Хорошей практикой является создание файла конфигурации tsconfig.json. Этот файл сообщает компилятору, как именно нужно обрабатывать ваш код.

Выполните команду:

В вашей папке появится файл tsconfig.json. Давайте рассмотрим несколько ключевых настроек, которые вы можете там найти или изменить:

* target: Определяет версию JavaScript, в которую будет скомпилирован ваш код (например, es6 или es2016). * module: Указывает систему модулей (например, commonjs для Node.js). * strict: Включает строгий режим проверки типов. Рекомендуется всегда держать эту опцию включенной (true), чтобы извлечь максимум пользы из TypeScript. * outDir: Папка, куда будут складываться скомпилированные .js файлы.

Ваша первая программа

Создайте файл с названием index.ts. Обратите внимание на расширение .ts — оно используется для файлов TypeScript.

Напишем простой код:

Здесь мы явно указали, что переменная message должна быть строкой (: string).

Чтобы запустить этот код, нам нужно сначала скомпилировать его. Введите в терминале:

После выполнения команды в папке появится файл index.js. Это обычный JavaScript, который можно запустить с помощью Node.js:

В консоли вы увидите: Привет, мир TypeScript!.

Базовые типы данных

Система типов — это сердце TypeScript. Она позволяет описывать форму данных и гарантировать, что вы не попытаетесь, например, умножить строку на объект. Рассмотрим основные примитивы.

Boolean (Логический тип)

Самый простой тип данных, который имеет всего два значения: true (истина) или false (ложь).

Number (Числовой тип)

В TypeScript, как и в JavaScript, все числа являются числами с плавающей точкой. Тип number используется как для целых, так и для дробных чисел. Также поддерживаются шестнадцатеричные, двоичные и восьмеричные литералы.

String (Строковый тип)

Тип string используется для работы с текстовыми данными. Вы можете использовать двойные кавычки ", одинарные ' или обратные кавычки ` ` для шаблонных строк.

Array (Массив)

Массивы можно типизировать двумя способами. Первый — использование типа элементов, за которым следуют квадратные скобки [].

Второй способ — использование обобщенного типа (Generics) Array<type>:

Оба способа идентичны по функциональности, выбор зависит от стиля кода вашей команды.

Tuple (Кортеж)

Кортеж позволяет выразить массив с фиксированным количеством элементов, типы которых известны, но не обязательно одинаковы. Это полезно, когда вам нужно вернуть несколько значений из функции или описать структуру данных строгого формата.

!Иллюстрация различия: массив хранит список однотипных данных, кортеж — фиксированную последовательность разных типов.

Enum (Перечисление)

Enum — это способ дать более дружелюбные имена наборам числовых значений. По умолчанию перечисления начинают нумерацию с 0.

Вы также можете вручную задать значения:

Any (Любой тип)

Иногда нам неизвестен тип переменной, особенно если данные приходят от пользователя или сторонних библиотек. В таких случаях можно использовать тип any.

Важно: Используйте any только в крайних случаях. Чрезмерное использование any лишает вас преимуществ TypeScript, превращая код обратно в нетипизированный JavaScript.

Void, Null и Undefined

* void: Обычно используется как возвращаемый тип функций, которые ничего не возвращают.

* null и undefined: В TypeScript это отдельные типы, которые имеют одноименные значения. По умолчанию они являются подтипами всех других типов (если не включена опция strictNullChecks), но лучше использовать их явно.

Вывод типов (Type Inference)

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

Это называется выводом типов. Хорошей практикой считается позволять компилятору выводить типы там, где это очевидно, чтобы код оставался чистым и читаемым.

Заключение

Мы успешно установили окружение, настроили tsconfig.json и разобрали фундаментальные строительные блоки TypeScript — базовые типы данных. Понимание разницы между Array и Tuple, умение работать с Enum и знание того, когда избегать any`, — это первый шаг к написанию надежного кода.

В следующей статье мы углубимся в более сложные концепции, такие как интерфейсы и типизация функций, которые позволят вам описывать сложные структуры данных вашего приложения.

2. Работа со сложными структурами: интерфейсы, псевдонимы типов и перечисления

Работа со сложными структурами: интерфейсы, псевдонимы типов и перечисления

В предыдущей статье мы познакомились с примитивными типами данных: строками, числами и логическими значениями. Однако реальные приложения редко оперируют только простыми значениями. Мы работаем с пользователями, товарами, заказами — сложными объектами, которые имеют множество свойств.

В этой части курса мы разберем инструменты TypeScript, позволяющие описывать форму объектов и создавать собственные типы данных. Это интерфейсы (interface), псевдонимы типов (type) и расширенные возможности перечислений (enum).

Интерфейсы (Interfaces)

Интерфейс в TypeScript — это способ определить «контракт» для объекта. Он описывает, какие свойства и методы должен иметь объект, чтобы соответствовать этому интерфейсу. Интерфейсы существуют только на этапе компиляции и полностью исчезают в итоговом JavaScript-коде.

Объявление и использование

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

Давайте создадим интерфейс User:

Если мы попытаемся не указать одно из свойств или задать неверный тип (например, строку вместо числа для age), TypeScript немедленно выдаст ошибку.

Необязательные свойства

Не все данные всегда обязательны. Например, у пользователя может не быть номера телефона. Для обозначения необязательных свойств используется знак вопроса ? после имени свойства.

Свойства только для чтения (Readonly)

Иногда нам нужно гарантировать, что поле объекта не будет изменено после его создания (например, id пользователя). Для этого используется модификатор readonly.

Псевдонимы типов (Type Aliases)

TypeScript позволяет создавать псевдонимы для типов с помощью ключевого слова type. На первый взгляд они очень похожи на интерфейсы, но имеют более широкую область применения.

Базовый синтаксис

Однако type может описывать не только объекты, но и примитивы, объединения и кортежи.

Объединения (Union Types)

Это одна из самых мощных возможностей type. Вы можете сказать, что переменная может быть или одного типа, или другого.

Пересечения (Intersection Types)

С помощью символа & можно объединять несколько типов в один, создавая новый тип, который содержит свойства всех исходных.

!Визуализация концепции пересечения типов: новый тип требует наличия свойств обоих родительских типов.

Интерфейс или Тип: что выбрать?

Это один из самых частых вопросов на собеседованиях. Во многих случаях они взаимозаменяемы, но есть ключевые различия.

  • Расширение (Extends):
  • Интерфейсы используют ключевое слово extends для наследования.

    Типы используют пересечение & для достижения похожего эффекта, но это не совсем наследование.

  • Слияние деклараций (Declaration Merging):
  • Это уникальная особенность интерфейсов. Если вы объявите один и тот же интерфейс дважды, TypeScript автоматически объединит их.

    С type такое невозможно — вы получите ошибку дублирования идентификатора.

  • Назначение:
  • * Используйте interface, когда описываете форму объекта или классы. * Используйте type, когда нужны объединения (|), пересечения (&), кортежи или псевдонимы для примитивов.

    > "В большинстве случаев вы можете выбирать исходя из личных предпочтений, но мы рекомендуем использовать interface до тех пор, пока вам не понадобятся специфические возможности type." — Документация TypeScript

    Углубление в Перечисления (Enums)

    В прошлой статье мы коснулись enum поверхностно. Давайте разберем их детальнее.

    Числовые перечисления

    По умолчанию enum — это числа. Если не задать значения, они начинаются с 0 и увеличиваются на 1.

    Вы можете изменить старт:

    Строковые перечисления

    Строковые перечисления не имеют автоинкремента, но они гораздо удобнее при отладке, так как хранят понятные значения, а не просто числа.

    Const Enums

    Для оптимизации производительности можно использовать const enum. В отличие от обычных перечислений, они полностью удаляются при компиляции, а в места их использования подставляются конкретные значения.

    В скомпилированном JS это превратится просто в:

    Это уменьшает размер итогового бандла.

    Практический пример: Система заказов

    Давайте объединим полученные знания и опишем небольшую систему заказов.

    Этот код наглядно демонстрирует, как разные конструкции TypeScript работают вместе, обеспечивая строгую типизацию и понятную структуру данных.

    Заключение

    Сегодня мы сделали большой шаг вперед, изучив инструменты для моделирования сложных данных. Интерфейсы и типы — это фундамент архитектуры любого TypeScript-приложения. Понимание того, когда использовать interface для расширяемости, а когда type для гибких объединений, приходит с практикой.

    В следующей статье мы перейдем к динамике: разберем типизацию функций, стрелочные функции и перегрузку методов.

    3. Функции и классы: типизация методов и принципы ООП в TypeScript

    Функции и классы: типизация методов и принципы ООП в TypeScript

    Добро пожаловать в третью часть курса «Полное руководство по TypeScript». В предыдущих статьях мы научились настраивать окружение и моделировать данные с помощью интерфейсов и типов. Теперь пришло время вдохнуть жизнь в наши приложения.

    Данные сами по себе статичны. Чтобы приложение работало, нам нужны механизмы для обработки этих данных. В этой статье мы разберем, как TypeScript усиливает работу с функциями, и погрузимся в объектно-ориентированное программирование (ООП), изучив классы, модификаторы доступа и наследование.

    Типизация функций

    Функции — это основной строительный блок любого приложения на JavaScript и TypeScript. TypeScript позволяет нам строго определить, что функция принимает на вход и что она возвращает.

    Базовая типизация

    При объявлении функции мы указываем типы для каждого параметра и тип возвращаемого значения.

    Если функция ничего не возвращает, используется тип void.

    Необязательные параметры и параметры по умолчанию

    В JavaScript все параметры функции являются необязательными. В TypeScript, по умолчанию, компилятор требует передать аргументы для всех объявленных параметров. Чтобы сделать параметр необязательным, мы используем знак вопроса ?.

    Важно: Необязательные параметры всегда должны идти после обязательных.

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

    REST-параметры

    Иногда мы не знаем заранее, сколько аргументов будет передано в функцию. Для этого используется оператор ... (rest operator), который собирает аргументы в массив.

    Перегрузка функций (Overloading)

    JavaScript — очень динамичный язык. Одна и та же функция может принимать разные типы данных и возвращать разные результаты. TypeScript поддерживает это через механизм перегрузки.

    Перегрузка позволяет объявить несколько сигнатур для одной функции.

    Обратите внимание: только первые две строки являются «видимыми» для внешнего кода. Функция реализации скрыта от прямого вызова с неправильными аргументами.

    Классы и ООП в TypeScript

    TypeScript предлагает полноценную поддержку классов, приближая разработку к стандартам таких языков, как C# или Java. Классы в TypeScript компилируются в функции-конструкторы или классы ES6 (в зависимости от настройки target), но на этапе разработки они предоставляют мощные инструменты типизации.

    Структура класса

    В отличие от JavaScript, в TypeScript мы должны объявлять свойства класса заранее.

    Модификаторы доступа

    Это одна из главных причин использовать классы в TypeScript. Модификаторы позволяют управлять видимостью свойств и методов, реализуя принцип инкапсуляции.

  • public (по умолчанию): Свойство или метод доступны отовсюду.
  • private: Доступ только внутри самого класса. Даже наследники не имеют доступа.
  • protected: Доступ внутри класса и в классах-наследниках.
  • !Визуализация областей видимости модификаторов доступа

    Пример использования:

    Сокращенная инициализация (Parameter Properties)

    TypeScript предлагает удобный синтаксис для объявления свойств прямо в конструкторе. Это избавляет от написания шаблонного кода.

    Вместо этого:

    Можно написать так:

    Readonly свойства

    С помощью модификатора readonly можно сделать свойства доступными только для чтения. Их значение можно установить только при объявлении или в конструкторе.

    Наследование и Абстрактные классы

    Наследование

    Как мы видели в примере с Employee, классы могут наследовать свойства и методы других классов с помощью ключевого слова extends. Если в дочернем классе есть свой конструктор, вы обязаны вызвать super() перед обращением к this.

    Абстрактные классы

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

    !Абстрактный класс задает контракт, который обязаны выполнить наследники

    Реализация интерфейсов

    В предыдущей статье мы изучили интерфейсы. Классы могут реализовывать интерфейсы с помощью ключевого слова implements. Это гарантирует, что класс соответствует определенному контракту.

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

    Геттеры и Сеттеры

    TypeScript поддерживает геттеры и сеттеры для перехвата доступа к свойствам объекта. Это позволяет добавить логику при чтении или записи данных.

    Заключение

    Мы разобрали, как TypeScript превращает работу с функциями и классами в строгий и предсказуемый процесс. Использование модификаторов доступа (private, protected, public) и абстрактных классов позволяет строить надежную архитектуру приложения, скрывая детали реализации и предоставляя четкие интерфейсы взаимодействия.

    В следующей статье мы перейдем к одной из самых сложных, но необходимых тем — Обобщениям (Generics). Они позволят нам создавать компоненты, способные работать с различными типами данных, сохраняя при этом строгую типизацию.

    4. Гибкость кода: использование обобщений (Generics) и утилитарных типов

    Гибкость кода: использование обобщений (Generics) и утилитарных типов

    Добро пожаловать в четвертую часть курса «Полное руководство по TypeScript». В предыдущих статьях мы научились создавать строгие структуры данных с помощью интерфейсов и классов, а также типизировать функции. Мы добились того, что наш код стал безопасным и предсказуемым.

    Однако, иногда строгая типизация может казаться оковами. Что делать, если мы хотим написать функцию, которая работает с любым типом данных, но при этом сохраняет информацию о нем? В JavaScript мы просто не указывали типы. В TypeScript новички часто прибегают к типу any, что сводит на нет все преимущества языка.

    Сегодня мы изучим Обобщения (Generics) — инструмент, который позволяет создавать компоненты, способные работать с различными типами данных, не теряя при этом строгой типизации. Также мы рассмотрим Утилитарные типы — встроенные инструменты TypeScript для трансформации уже существующих типов.

    Что такое Обобщения (Generics)?

    Представьте, что вы создаете конвейер на заводе. Если вы настроите его только на производство красных кубиков, он будет бесполезен для синих шариков. Если вы сделаете его универсальным, но не будете контролировать, что выходит на выходе, вы получите хаос. Обобщения позволяют создать конвейер, который принимает «чертеж» (тип) в момент запуска и гарантирует, что на выходе получится продукт именно по этому чертежу.

    !Иллюстрация принципа работы Generics: функция принимает тип как параметр и использует его для обработки данных.

    Проблема дублирования кода

    Рассмотрим простую функцию, которая возвращает переданное ей значение. Без Generics нам пришлось бы писать отдельные функции для каждого типа или использовать any.

    Использование any плохо тем, что компилятор «забывает», какой тип был передан. Если мы передадим число, а вернется any, мы можем случайно попытаться вызвать у него метод строки, и компилятор нас не остановит.

    Синтаксис Generics

    Обобщения позволяют нам захватить тип переданного аргумента. Для этого используется специальная переменная типа, которую обычно обозначают буквой T (от слова Type), заключенной в угловые скобки < >.

    Разберем этот код:

  • <T> после имени функции сообщает TypeScript, что это обобщенная функция.
  • arg: T означает, что аргумент будет того же типа T.
  • : T после скобок означает, что функция вернет значение того же типа T.
  • Теперь мы можем использовать эту функцию для любых типов:

    Более того, TypeScript обладает мощным механизмом вывода типов. Нам часто даже не нужно указывать <string> или <number> явно:

    Работа с переменными типа

    Важно понимать, что внутри обобщенной функции TypeScript рассматривает T как любой возможный тип. Это накладывает ограничения. Вы не можете использовать методы, специфичные только для чисел или строк, если не доказали TypeScript, что T их поддерживает.

    Если мы хотим работать с массивом элементов типа T, мы должны явно это указать:

    Теперь функция читается так: «Принимает массив элементов типа T и возвращает массив элементов типа T».

    Обобщенные интерфейсы и классы

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

    Generic Interfaces

    Представьте, что у нас есть интерфейс для ответа от сервера, который всегда содержит статус, но данные (data) могут быть разными.

    Generic Classes

    Классы также могут быть обобщенными. Это особенно полезно при создании структур данных, таких как стеки, очереди или хранилища.

    Ограничения обобщений (Constraints)

    Иногда мы хотим, чтобы функция работала не с любым типом, а только с теми, которые соответствуют определенным критериям. Для этого используется ключевое слово extends.

    Вернемся к примеру с length. Мы хотим, чтобы функция принимала любой тип, у которого есть свойство length (строки, массивы, специальные объекты).

    Здесь T extends Lengthwise означает: «Тип T может быть чем угодно, но он обязан иметь все свойства интерфейса Lengthwise».

    Использование keyof в ограничениях

    Частый сценарий: нам нужно получить значение свойства объекта по имени ключа. Чтобы гарантировать, что ключ действительно существует в объекте, мы используем оператор keyof.

    В этом примере мы объявили два параметра типа: T (сам объект) и K (ключ). Запись K extends keyof T означает, что K может быть только одним из имен свойств типа T.

    Утилитарные типы (Utility Types)

    TypeScript предоставляет набор встроенных обобщенных типов, которые помогают трансформировать типы. Это избавляет от необходимости создавать множество дублирующих интерфейсов. Рассмотрим самые популярные из них.

    Partial<T>

    Делает все свойства типа T необязательными. Это идеально подходит для функций обновления объектов, когда мы меняем только часть полей.

    Readonly<T>

    Делает все свойства типа T доступными только для чтения. Это полезно для защиты данных от мутаций.

    Pick<T, K>

    Создает новый тип, выбирая только указанные свойства K из типа T. Полезно, когда нужно передать только часть большого объекта.

    Omit<T, K>

    Противоположность Pick. Создает новый тип, исключая указанные свойства K из типа T. Часто используется для удаления чувствительных данных (например, паролей) перед отправкой на клиент.

    Record<K, T>

    Используется для создания типа объекта (словаря), где ключи имеют тип K, а значения — тип T.

    !Визуальное представление того, как утилитарные типы изменяют структуру исходного интерфейса.

    Заключение

    Обобщения (Generics) — это мост между гибкостью JavaScript и надежностью TypeScript. Они позволяют писать код, который легко переиспользовать для разных типов данных, не жертвуя при этом проверкой типов. Утилитарные типы, такие как Partial, Pick и Omit, еще больше упрощают разработку, позволяя конструировать новые типы на основе существующих, избегая дублирования.

    В следующей статье мы рассмотрим Декораторы — мощный инструмент метапрограммирования, который широко используется в таких фреймворках, как Angular и NestJS.

    5. Продвинутые техники: сужение типов, декораторы и настройка tsconfig.json

    Продвинутые техники: сужение типов, декораторы и настройка tsconfig.json

    Добро пожаловать в пятую часть курса «Полное руководство по TypeScript». Мы уже прошли долгий путь: от базовых типов до сложных интерфейсов, классов и обобщений (Generics). Ваш код стал строгим и типизированным.

    Однако TypeScript — это не просто статический анализатор. Это инструмент, который умеет адаптироваться к логике вашего кода. В этой статье мы рассмотрим, как научить компилятор «понимать» ваши проверки условий (сужение типов), как использовать метапрограммирование через декораторы и как настроить «сердце» проекта — файл tsconfig.json, чтобы извлечь максимум пользы из языка.

    Сужение типов (Type Narrowing)

    Одна из самых частых ситуаций в TypeScript — это работа с переменной, которая может иметь несколько типов (Union Types). Например, аргумент функции может быть string | number. Чтобы работать с этой переменной безопасно, нам нужно «сузить» её тип до конкретного значения внутри блока кода.

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

    !Визуализация процесса сужения типов: из множества возможных вариантов мы отсеиваем лишние с помощью проверок.

    Type Guards (Защитники типа)

    Самый простой способ сузить тип — использовать стандартные конструкции JavaScript. TypeScript достаточно умен, чтобы анализировать их.

    #### Оператор typeof

    Используется для проверки примитивов.

    Если бы мы не сделали проверку, TypeScript выдал бы ошибку, так как метод repeat не существует у типа string.

    #### Оператор instanceof

    Используется для проверки принадлежности объекта к классу. Это полезно при работе с классами и ошибками.

    Пользовательские защитники типа (User-Defined Type Guards)

    Иногда логика проверки типа слишком сложна для простого typeof. В этом случае мы можем написать функцию, которая возвращает предикат типа.

    Предикат типа записывается как parameterName is Type в месте возвращаемого значения функции.

    Ключевая часть здесь — pet is Fish. Если функция вернет true, TypeScript сузит тип переменной pet до Fish в вызывающем коде.

    Дискриминируемые объединения (Discriminated Unions)

    Это мощный паттерн, который часто используется в Redux или при обработке ответов API. Идея заключается в том, чтобы добавить общее поле (обычно kind, type или tag) с литеральным типом в каждый интерфейс объединения.

    Благодаря полю kind, TypeScript безошибочно определяет, с какой фигурой мы работаем внутри каждого case.

    Декораторы (Decorators)

    Декораторы — это специальная возможность, позволяющая добавлять аннотации и метапрограммирование к объявлению классов и их членов. Простыми словами, декоратор — это функция, которая «обертывает» класс, метод или свойство, позволяя изменить их поведение.

    > Важно: Декораторы являются экспериментальной функцией в TypeScript (хотя широко используются в Angular и NestJS). Для их работы необходимо включить опцию experimentalDecorators в tsconfig.json.

    !Декораторы работают как обертки: они могут перехватывать выполнение, изменять входные данные или результат выполнения функции.

    Синтаксис

    Декоратор использует символ @ перед именем функции.

    В данном примере декоратор Logger вызовется в момент определения класса.

    Декораторы методов

    Наиболее полезный тип декораторов. Они позволяют модифицировать поведение метода, например, добавить логирование или проверку прав доступа.

    Здесь мы подменили оригинальный метод add на новый, который сначала логирует данные, а потом вызывает оригинальный код.

    Настройка tsconfig.json

    Файл tsconfig.json — это командный центр вашего проекта. Он указывает компилятору, как именно превращать TypeScript в JavaScript. Давайте разберем критически важные настройки.

    Чтобы создать файл конфигурации автоматически, используйте команду:

    Основные опции

    | Опция | Описание | | :--- | :--- | | target | Версия ECMAScript, в которую будет скомпилирован код (например, ES5, ES2020). Если вам нужно поддерживать старые браузеры, выбирайте ES5. | | module | Система модулей (например, CommonJS для Node.js или ESNext для современных фронтенд-сборщиков). | | outDir | Папка, куда будут складываться скомпилированные .js файлы (обычно ./dist или ./build). | | rootDir | Корневая папка с исходным кодом (обычно ./src). |

    Строгий режим (Strict Mode)

    Самая важная настройка — это "strict": true. Она включает в себя семейство проверок, которые делают ваш код максимально безопасным. Рекомендуется всегда включать её в новых проектах.

    Что она включает (среди прочего):

  • noImplicitAny: Запрещает использование типа any там, где TypeScript не может вывести тип сам. Это заставляет вас явно типизировать аргументы функций.
  • strictNullChecks: Запрещает присваивать null и undefined другим типам. Это спасает от самой частой ошибки — «Cannot read property of undefined».
  • Настройка путей (Paths)

    В больших проектах импорты могут выглядеть ужасно: import { User } from "../../../../models/user";

    С помощью настройки baseUrl и paths можно сделать их красивыми:

    Теперь импорт станет чище: import { User } from "@models/user";

    > Примечание: Для работы путей во время выполнения (runtime) вам могут понадобиться дополнительные настройки сборщика (Webpack, Vite) или плагины для Node.js, так как tsconfig влияет только на компиляцию, но не меняет пути в итоговом JS-файле.

    Заключение

    В этой статье мы углубились в возможности TypeScript, которые отличают профессиональный код от любительского. Мы научились:

    * Использовать Type Guards и Discriminated Unions для безопасной работы с динамическими данными. * Применять Декораторы для расширения функциональности классов без изменения их кода. * Настраивать tsconfig.json, чтобы компилятор стал вашим строгим, но справедливым наставником.

    Эти инструменты позволяют писать масштабируемые приложения, которые легко поддерживать и рефакторить. В следующей, заключительной статье курса, мы соберем все знания воедино и обсудим лучшие практики разработки и интеграцию TypeScript с популярными библиотеками, такими как React.