Знакомство с TypeScript: базовая типизация и ключевые возможности

Почему TypeScript?
Андерс Хейлсберг — именно этого человека принято считать создателем TypeScript. Инженер-программист, который подарил миру такие языки как: Turbo Pascal, Delphi и C#.
Основным мотивом создания TypeScript было желание решить проблемы, связанные с разработкой крупных и сложных приложений на JavaScript.
Думаю, многие кто работал с большими проектами замечал, как порой бывает сложно рефакторить или даже просто понимать структуру данных , а чаще всего вообще невозможно. Именно этими проблемами и "занимается" TypeScript. На данном этапе стоит уточнить, что TypeScript представляет собой расширенную версию JavaScript, содержащую в себе все основные возможности языка JavaScript, дополненные некоторыми расширениями.
Основной причиной использования TypeScript является возможность добавления статической типизации к JavaScript. Переменные с статической типизацией имеют тип, который не может быть изменен после их объявления. Это позволяет предотвратить множество потенциальных ошибок.
Проблемы JavaScript:

Динамические типы.
Эта ситуация может привести к непредсказуемому поведению программы и ошибкам в ее работе, особенно в случае больших и сложных проектов, где легко потеряться в типах данных, особенно при дальнейшем изменении кода разработчиками, которые не были в курсе таких манипуляций с переменными.let x = 10; console.log(x + 5); // Вывод: 15 x = "10"; // Переопределяем переменную x строкой console.log(x + 5); // Вывод: "105"
Отсутствие Type Safety
Отсутствие Type Safety в JavaScript означает, что язык не предоставляет строгой проверки типов данных на этапе компиляции или выполнения. В отличие от JavaScript, TypeScript требует, чтобы разработчики явно указывали типы данных для переменных, функций и других элементов кода. Это позволяет предотвратить ошибки, связанные с неправильными типами данных, ещё до запуска программы.
Чтобы обеспечить безопасность типов данных, TypeScript предоставляет два подхода:
Время выполнения (Runtime): TypeScript предоставляет информацию о типах данных во время выполнения программы, используя API Runtime Type Information (RTTI). Это позволяет проверять типы данных и обрабатывать их во время выполнения, что может быть полезно для некоторых операций.
Время компиляции (Compile Time): TypeScript обеспечивает защиту типов данных на этапе компиляции. Это означает, что множество ошибок, связанных с типами данных, могут быть обнаружены и исправлены ещё до запуска программы. Компилятор TypeScript проверяет соответствие типов данных и предупреждает о возможных проблемах, что помогает создавать более надежный и безопасный код.
Таким образом, TypeScript предоставляет средства как для обеспечения безопасности типов данных во время выполнения программы, так и для предотвращения ошибок на этапе компиляции, что делает процесс разработки более эффективным и надежным.
Autocomplete
В JavaScript, автодополнение может быть менее точным из-за динамической природы языка. Редакторы и интегрированные среды разработки (IDE) могут предлагать автодополнение на основе контекста и доступных методов и свойств объектов. Однако, из-за отсутствия строгой статической типизации, автодополнение может быть менее точным и предложения могут быть менее информативными.
В TypeScript, благодаря статической типизации, автодополнение обычно более точное и полезное. Редакторы и IDE могут использовать информацию о типах данных, объявленных в коде, чтобы предлагать точные методы и свойства для объектов, а также предупреждать о возможных ошибках. Это делает процесс написания кода более продуктивным и позволяет разработчикам избегать многих ошибок.

Начало работы
Для начала работы с TypeScript, нужно либо настроить специальный интерфейс командной строки (CLI), либо воспользоваться онлайн-песочницей или альтернативными инструментами. Для выполнения кода потребуется использовать Node.js. Давайте создадим новый проект:
Создайте новую директорию для проекта и перейдите в неё.
Инициализируйте новый Node.js-проект с помощью
npm init -y
.Установите компилятор TypeScript локально для текущего проекта с помощью
npm i typescript
.
Теперь, чтобы убедиться, что всё работает, создайте файл index.ts
с каким-либо кодом и транспилируйте его в JavaScript с помощью npx tsc index.ts
. Наконец, запустите скомпилированный код с помощью Node.js.
Обратите внимание, что устанавливать TypeScript лучше локально и использовать его через npx
, так как версии могут отличаться, и это поможет избежать проблем совместимости.
Что же такое tsc?
TSC
- это сокращение от TypeScript Compiler, то есть компилятор TypeScript. Он отвечает за преобразование файлов с расширением .ts
(код на TypeScript) в файлы с расширением .js
(код на JavaScript), который может быть исполнен браузером или Node.js.
Несколько основных флагов tsc
:
--target
: Устанавливает версию JavaScript, на которую будет скомпилирован TypeScript код.--outFile
или-o
: Позволяет указать файл, в который будет сохранён скомпилированный JavaScript.--watch
или-w
: Запускает компилятор в режиме наблюдения, при котором он следит за изменениями файлов и автоматически перекомпилирует их при необходимости.--strict
: Включает строгий режим, в котором TypeScript проверяет код на более широкий спектр ошибок.--module
или-m
: Указывает тип модуля, используемого в JavaScript коде.
Это лишь небольшой набор флагов tsc
, который можно использовать для настройки процесса компиляции TypeScript кода под конкретные потребности проекта.
Базовая типизация
Примитивные типы
Если вы ранее работали с JavaScript, думаю, вам не составит большой сложности понять основные типы TypeScript. В отличие от JavaScript, где типы данных могут быть динамически определены во время выполнения программы, TypeScript предлагает статическую типизацию, позволяющую определить типы данных на этапе компиляции. Это означает, что вы можете объявлять типы переменных, параметров функций, возвращаемых значений и других элементов вашего кода заранее, что повышает надежность и понятность вашего кода.
К примитивным типам можно отнести:
Number
По данному примеру можно увидеть какой синтаксис предоставляет нам TypeScript для типизации переменных. Достаточно просто объявить переменную и через двоеточие указать желаемый тип.const age: number = 52; console.log(age.split('')) // Property 'split' does not exist on type 'number'.
String
const city: string = "Питер"; console.log(city + 52); // Это не ошибка , TypeScript понимает , // что у нас в данный момент конкатенация console.log(Math.pow(city, 3)); // Argument of type 'string' // is not assignable to parameter of type 'number'.
Boolean
// Пример правильного использования let x: number = 10; let y: number = 5; let isGreaterThan: boolean = x > y; console.log(isGreaterThan); // true // Пример с ошибкой let isRead: boolean = 42; // Type 'number' is not assignable to type 'boolean'.
Null
Часто мы сталкиваемся с таким использованиемnull
. Не стоит беспокоиться о "палке" между типами, подробнее с ней ознакомимся к концу статьи.
Этот оператор говорит TypeScript о том, что мы предполагаем, что наша переменная может принимать значения одного из перечисленных типов. Здесь сразу хочется отметить, что это не логический оператор||
)из JavaScript.let myVar: string | null = null; console.log(myVar); // Вывод: null myVar = "Hello"; console.log(myVar); // Вывод: Hello
Undefined
В случае сundefined
также применяется оператор объединения типов (|
), который позволяет переменной принимать либо определенный тип данных, либо значениеundefined
.let myVar: string | undefined; console.log(myVar); // Вывод: undefined myVar = "Hello"; console.log(myVar); // Вывод: Hello myVar = 42; // Type 'number' is not assignable to type 'string'.
Symbol
В TypeScript типsymbol
используется для представления символьных значений, точно также как и в обычном JavaScript. Вот пример типизации символа:let mySymbol: symbol = Symbol("foo");
BigInt
Типbigint
в TypeScript используется для представления целых чисел произвольной длины. Этот тип добавлен в стандарт ECMAScript 2020 и позволяет работать с числами, которые превышают максимальное значение, представленное типомnumber
.let bigIntValue: bigint = 1234567890123456789012345678901234567890n;
Literal Types
Литералы являются точными значениями, предоставляемыми самим JavaScript, и могут быть использованы в TypeScript для явного указания конкретных значений переменных. Литеральный тип данных в TypeScript представляет собой ограничение набора допустимых значений переменной до определенных литеральных значений.// Строковые литералы: let color: "red" | "green" | "blue"; color = "red"; // Верно color = "yellow"; // Ошибка: Недопустимое значение // Числовые литералы: let status: 200 | 404 | 500; status = 200; // Верно status = 401; // Ошибка: Недопустимое значение // Логические литералы: let isEnabled: true | false; isEnabled = true; // Верно isEnabled = "false"; // Ошибка: Недопустимое значение
Составные типы
Составные типы данных в TypeScript представляют собой типы, которые состоят из комбинации других типов данных. Они позволяют описывать структурированные данные, такие как объекты, массивы или кортежи. Вот несколько примеров составных типов данных в TypeScript:
Object Type
type Person = { name: string; age: number; isStudent: boolean; };
В этом примере
Person
представляет собой тип объекта, который состоит из трех свойств:name
,age
иisStudent
, каждое из которых имеет свой собственный тип данных.Array Type
let numbers: number[] = [1, 2, 3, 4, 5]; let names: Array<string> = ["Tom", "Bob", "Alice"];
В этом примере
numbers
является массивом чисел (number[]
), содержащим элементы типаnumber
. Также представлен альтернативный способ объявления массива с использованием generics. Здесьnames
- это массив строк (Array<string>
), в котором каждый элемент имеет типstring
. Более подробно о generics мы поговорим позже.Tuples
let tuple: [string, number, boolean]; tuple = ["hello", 10, true]; let matrix: [number, number, number][] = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ];
Кортежи (Tuples) в TypeScript представляют собой упорядоченные коллекции фиксированной длины, которые могут содержать элементы различных типов данных. В отличие от массивов, где каждый элемент имеет одинаковый тип, кортежи могут иметь различные типы данных для каждого элемента.
Union Types
type Result = "success" | "error"; function processResult(result: Result) { // Обработка результата } processResult("success"); // Верно processResult("fail"); // Ошибка: Недопустимое значение
Union типы также могут использоваться с более сложными типами данных, такими как объекты, перечисления и даже другие union типы.
В этом примере
Result
представляет собой union тип, который может быть либо"success"
, либо"error"
. ФункцияprocessResult
принимает аргументresult
, который должен быть одним из этих значений.Intersection Types
interface Animal { name: string; age: number; } interface Flyable { fly: () => void; } type Bird = Animal & Flyable; function birdInfo(bird: Bird) { console.log(`Name: ${bird.name}`); console.log(`Age: ${bird.age}`); bird.fly(); } let myBird: Bird = { name: "Sparrow", age: 2, fly: () => console.log("Flying...") }; birdInfo(myBird);
В этом примере создается интерфейс
Animal
, которая представляет собой общие свойства для животных, и интерфейсFlyable
, которая представляет собой способность к полету. Затем создается новый типBird
, который представляет собой пересечение типовAnimal
иFlyable
. Таким образом, объекты типаBird
должны содержать свойства как животных, так и способность к полету.Затем функция
birdInfo
принимает объект типаBird
и выводит информацию о птице, включая ее имя и возраст, а также вызывает методfly
, который представлен в интерфейсеFlyable
.Intersection Types полезны, когда нужно объединить свойства из нескольких типов данных в один тип. Это позволяет создавать более сложные типы данных, которые содержат комбинацию функциональности из различных источников.
На данном этапе не нужно углубляться что такоеinterface
, если быть кратким, то это способ описать какую-либо структуру, более подробнее мы поговорим оtype
иinterface
чуть позже.
Специальные типы данных

Any
Типany
позволяет переменной принимать значения любого типа данных. Использованиеany
отключает проверку типов во время компиляции TypeScript.
Использованиеany
полезно в ситуациях, когда тип данных переменной неизвестен заранее или когда требуется обработка разных типов данных в одной переменной без строгой типизации. В. остальных же случаях старайтесь его избегать.let myVar: any; myVar = 10; // число myVar = "hello"; // строка myVar = true; // булево значение
Unknown
Типunknown
представляет значение, о типе которого мы ничего не знаем. Он более безопасен, чемany
, потому что нельзя просто так использовать значение типаunknown
.unknown
часто используется в ситуациях, когда тип данных неизвестен и требуется безопасная обработка значений разных типов.let userInput: unknown; userInput = 10; // число userInput = "hello";// строка // Необходимо выполнить дополнительные проверки перед использованием значения типа unknown if (typeof userInput === 'string') { console.log(userInput.toUpperCase()); }
Void
Типvoid
используется для указания на то, что функция не возвращает никакого значения.Функция
logMessage
ничего не возвращает (возвращаемый тип -void
), она просто выводит сообщение на консоль.void
также используется в контексте переменных, которым не присваивается никакое значение.function logMessage(message: string): void { console.log(message); }
Never
Типnever
представляет собой тип данных, который указывает на то, что функция никогда не завершается нормально.
ФункцияthrowError
бросает ошибку и никогда не возвращает управление.never
также используется в случаях, когда функция содержит бесконечный цикл или всегда выбрасывает ошибку.function throwError(message: string): never { throw new Error(message); }
object
Типobject
представляет любой объект JavaScript: это может быть объект, массив, функция, класс и т. д. Но он не включает в себя примитивные типы данных (number
,string
,boolean
,symbol
,null
илиundefined
).let obj: object; obj = { name: "John", age: 30 }; // объект obj = [1, 2, 3]; // массив obj = function() { console.log("Hello"); }; // функция
Подведение итогов
Разумный выбор TypeScript обоснован множеством факторов. Во-первых, его строгая типизация обеспечивает более надежный код и предотвращает множество потенциальных ошибок на этапе разработки. Это позволяет сократить время, затраченное на отладку, и снизить вероятность возникновения проблем в процессе эксплуатации. Кроме того, TypeScript поддерживает современные возможности JavaScript, что позволяет использовать последние языковые конструкции и функции. Его активное сообщество и широкие возможности интеграции с другими технологиями делают его привлекательным выбором для разработчиков, стремящихся к созданию масштабируемых и поддерживаемых проектов в сфере веб-разработки.
Также, хочется оставить удобную шпаргалку, которую я нашел на просторах Интернета, к которой вы можете обратиться, если что-то забыли или, наоборот, узнать новое, чего не было сказано в статье.
