Мы продолжаем серию публикаций адаптированного и дополненного перевода  "Карманной книги по TypeScript".
 Другие части: Обратите внимание: для большого удобства в изучении книга была оформлена в виде прогрессивного веб-приложения. В JS часто используется 3 примитива: string, number и boolean. Каждый из них имеет соответствующий тип в TS: Обратите внимание: типы String, Number и Boolean (начинающиеся с большой буквы) являются легальными и ссылаются на специальные встроенные типы, которые, однако, редко используются в коде. Для типов всегда следует использовать string, number или boolean. Для определения типа массива  можно использовать синтаксис number[]; такой синтаксис подходит для любого типа (например, string[] — это массив строк и т.д.). Также можно встретить Array<number>, что означает тоже самое. Такой синтаксис, обычно, используется для определения общих типов или дженериков (generics). Обратите внимание:  — это другой тип, кортеж (tuple). TS предоставляет специальный тип any, который может использоваться для отключения проверки типов: Тип any может быть полезен в случае, когда мы не хотим писать длинное определение типов лишь для того, чтобы пройти проверку. При отсутствии определения типа и когда TS не может предположить его на основании контекста, неявным типом значение становится any. Обычно, мы хотим этого избежать, поскольку any является небезопасным с точки зрения системы типов. Установка флага noImplicitAny позволяет квалифицировать любое неявное any как ошибку. При объявлении переменной с помощью const, let или var опционально можно определить ее тип: Однако, в большинстве случаев этого делать не требуется, поскольку TS пытается автоматически определить тип переменной на основе типа ее инициализатора, т.е. значения: В JS функции, в основном, используются для работы с данными. TS позволяет определять типы как для входных (input), так и для выходных (output) значений функции. При определении функции можно указать, какие типы параметров она принимает: Вот что произойдет при попытке вызвать функцию с неправильным аргументом: Обратите внимание: количество передаваемых аргументов будет проверяться даже при отсутствии аннотаций типа параметров. Также можно аннотировать тип возвращаемого функцией значения: Как и в случае с аннотированием переменных, в большинстве случаев TS может автоматически определить тип возвращаемого функцией значения на основе инструкции return. Анонимные функции немного отличаются от обычных. Когда функция появляется в месте, где TS может определить способ ее вызова, типы параметров такой функции определяются автоматически. Вот пример: Несмотря на отсутствие аннотации типа для s, TS использует типы функции forEach, а также предполагаемый тип массива для определения типа s. Этот процесс называется определением типа на основе контекста (contextual typing). Объектный тип — это любое значение со свойствами. Для его определения мы просто перечисляем все свойства объекта и их типы. Например, так можно определить функцию, принимающую объект с координатами: Для разделения свойств можно использовать , или ;. Тип свойства является опциональным. Свойство без явно определенного типа будет иметь тип any. Для определения свойства в качестве опционального используется символ ? после названия свойства: В JS при доступе к несуществующему свойству возвращается undefined. По этой причине, при чтении опционального свойства необходимо выполнять проверку на undefined: Обратите внимание: в литературе, посвященной TS, union, обычно, переводится как объединение, но фактически речь идет об альтернативных типах, объединенных в один тип. Объединение — это тип, сформированный из 2 и более типов, представляющий значение, которое может иметь один из этих типов. Типы, входящие в объединение, называются членами (members) объединения. Реализуем функцию, которая может оперировать строками или числами: В случае с объединениями, TS позволяет делать только такие вещи, которые являются валидными для каждого члена объединения. Например, если у нас имеется объединение string | number, мы не сможем использовать методы, которые доступны только для string: Решение данной проблемы заключается в сужении (narrowing) объединения. Например, TS знает, что только для string оператор typeof возвращает 'string': Другой способ заключается в использовании функции, такой как Array.isArray: В некоторых случаях все члены объединения будут иметь общие методы. Например, и массивы, и строки имеют метод slice. Если каждый член объединения имеет общее свойство, необходимость в сужении отсутствует: Что если мы хотим использовать один и тот же тип в нескольких местах? Для этого используются синонимы типов: Синонимы можно использовать не только для объектных типов, но и для любых других типов, например, для объединений: Обратите внимание: синонимы — это всего лишь синонимы, мы не можем создавать на их основе другие "версии" типов. Например, такой код может выглядеть неправильным, но TS не видит в нем проблем, поскольку оба типа являются синонимами одного и того же типа: Определение интерфейса — это другой способ определения типа объекта: TS иногда называют структурно типизированной системой типов (structurally typed type system) — TS заботит лишь соблюдение структуры значения, передаваемого в функцию printCoords, т.е. содержит ли данное значение ожидаемые свойства. Синонимы типов и интерфейсы очень похожи. Почти все возможности interface доступны в type. Ключевым отличием между ними является то, что type не может быть повторно открыт для добавления новых свойств, в то время как interface всегда может быть расширен. Пример расширения интерфейса: Пример расширения типа с помощью пересечения (intersection): Пример добавления новых полей в существующий интерфейс: Тип не может быть изменен после создания: Общее правило: используйте interface до тех пор, пока вам не понадобятся возможности type. В некоторых случаях мы знаем о типе значения больше, чем TS. Например, когда мы используем document.getElementById, TS знает лишь то, что данный метод возвращает какой-то HTMLElement, но мы знаем, например, что будет возвращен HTMLCanvasElement. В этой ситуации мы можем использовать утверждение типа для определения более конкретного типа: Для утверждения типа можно использовать другой синтаксис (е в TSX-файлах): TS разрешает утверждения более или менее конкретных версий типа. Это означает, что преобразования типов выполнять нельзя: Иногда это правило может быть слишком консервативным и мешать выполнению более сложных валидных преобразований. В этом случае можно использовать двойное утверждение: сначала привести тип к any (или unknown), затем к нужному типу: В дополнение к общим типам string и number, мы можем ссылаться на конкретные строки и числа, находящиеся на определенных позициях. Вот как TS создает типы для литералов: Сами по себе литеральные типы особой ценности не представляют: Но комбинация литералов с объединениями позволяет создавать более полезные вещи, например, функцию, принимающую только набор известных значений: Числовые литеральные типы работают похожим образом: Разумеется, мы можем комбинировать литералы с нелитеральными типами: При инициализации переменной с помощью объекта, TS будет исходить из предположения о том, что значения свойств объекта в будущем могут измениться. Например, если мы напишем такой код: TS не будет считать присвоение значения 1 полю, которое раньше имело значение 0, ошибкой. Это объясняется тем, что TS считает, что типом obj.counter является number, а не 0. Тоже самое справедливо и в отношении строк: В приведенном примере предположительный типом req.method является string, а не 'GET'. Поскольку код может быть вычислен между созданием req и вызовом функции handleRequest, которая может присвоить req.method новое значение, например, GUESS, TS считает, что данный код содержит ошибку. Существует 2 способа решить эту проблему. В JS существует два примитивных значения, сигнализирующих об отсутствии значения: null и undefined. TS имеет соответствующие типы. То, как эти типы обрабатываются, зависит от настройки strictNullChecks (см. часть 1). TS предоставляет специальный синтаксис для удаления null и undefined из типа без необходимости выполнения явной проверки. Указание ! после выражения означает, что данное выражение не может быть нулевым, т.е. иметь значение null или undefined: Перечисления позволяют описывать значение, которое может быть одной из набора именованных констант. Использовать перечисления не рекомендуется. Данный примитив используется для представления очень больших целых чисел BigInt: Подробнее о BigInt можно почитать здесь. Данный примитив используется для создания глобально уникальных ссылок с помощью функции Symbol(): Подробнее о символах можно почитать здесь. Облачные серверы от Маклауд идеально подходят для разработки на TypeScript. Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!