Введение в TypeScript
TypeScript — это язык программирования с открытым исходным кодом, разработанный компанией Microsoft. Это надмножество JavaScript, которое, будучи полностью совместимым с синтаксисом JavaScript, добавляет необязательную статическую систему типов и возможности объектно-ориентированного программирования на основе классов.
Код TypeScript в конечном итоге компилируется в чистый JavaScript и может выполняться в любой среде, поддерживающей JavaScript, включая браузеры, Node.js и мобильные платформы.

Почему TypeScript?
JavaScript — динамически типизированный язык; тип переменной можно определить только во время выполнения.
Эта гибкость хорошо работает в небольших проектах, но по мере роста масштаба проекта постепенно проявляются проблемы:
| Сценарий проблемы | Дилемма JavaScript | Решение TypeScript |
|---|---|---|
| Передача неверного типа в параметр функции | Ошибки появляются только во время выполнения, их сложно обнаружить заранее | Ошибки появляются во время компиляции, с подсказками IDE в реальном времени |
| Обращение к несуществующим свойствам | Возвращаетundefined, поведение непредсказуемо | Компилятор сразу сообщает об ошибке и отказывается пропускать это |
| Рефакторинг больших проектов | Изменишь в одном месте — неизвестно, что сломается | Система типов автоматически отслеживает все ссылки |
| Командная работа | Какие параметры принимает функция и что она возвращает, полностью зависит от комментариев или документации | Сигнатуры типов служат документацией, с автодополнением в IDE |
| Читаемость кода | Нельзя напрямую узнать структуру данных из определения функции | Интерфейсы и псевдонимы типов делают структуру данных понятной с первого взгляда |
Основная цель TypeScript — не заменить JavaScript, а сделать крупные проекты на JavaScript управляемыми и поддерживаемыми. Это «страховочная сеть» для JavaScript, а не конкурент.
Давайте рассмотрим самый наглядный пример:
Пример
function greet(name) {
return "Hello, " + name.toUpperCase();
}
greet(123); // Ошибка во время выполнения: name.toUpperCase не является функцией
Пример
function greet(name: string): string {
return "Hello, " + name.toUpperCase();
}
greet(123); // Ошибка компиляции: Аргумент типа 'number' не может быть присвоен параметру типа 'string'
greet("example"); // Правильно: Hello, EXAMPLE
Связь между TypeScript и JavaScript
Связь между TypeScript и JavaScript можно выразить одной фразой:TypeScript — это надмножество JavaScript, что означает, что весь допустимый код JavaScript также является допустимым кодом TypeScript.
Иллюстрация отношений множеств
JavaScript (весь код JS)
⊂ TypeScript (JS + система типов + новые возможности)
⊂ Скомпилированный вывод (стандартный JavaScript, может запускаться в любой среде)
Основные различия между ними:
| Пункт сравнения | JavaScript | TypeScript |
|---|---|---|
| Система типов | Динамическая типизация, определяется во время выполнения | Статическая типизация, проверяется во время компиляции (необязательно) |
| Способ выполнения | Запускается напрямую в браузере / Node.js | Должен быть скомпилирован в JS перед запуском |
| Момент обнаружения ошибок | Время выполнения | На этапе компиляции (обнаруживаются рано) |
| Поддержка IDE | Базовое автодополнение | Мощный вывод типов, точное автодополнение, поддержка рефакторинга |
| Кривая обучения | Относительно пологая | Требуется дополнительное изучение системы типов |
| Совместимость с существующим JS | — | Полностью совместим, можно мигрировать постепенно |
| Расширение файла | .js | .tsили.tsx(включая JSX) |
TypeScript поддерживает «постепенное внедрение»: не нужно переписывать весь проект сразу. Можно сначала
.jsизменение.ts, затем постепенно добавлять типы в ключевые модули, а существующий код продолжит работать как обычно.
Основные возможности
TypeScript представляет полноценную систему типов поверх JavaScript. Ниже перечислены наиболее часто используемые основные возможности.
Базовые аннотации типов
Объявляйте типы после переменных, параметров функций и возвращаемых значений с помощью двоеточия; это самый базовый синтаксис TypeScript.
Пример
let age: number = 25;
let username: string = "example";
let isActive: boolean = true;
// Типы массивов, два эквивалентных способа
let scores: number[] = [90, 85, 92];
let tags: Array<string> = ["typescript", "javascript"];
// Кортеж: массив с фиксированной длиной и типами
let point: [number, number] = [10, 20];
let entry: [string, number] = ["EXAMPLE", 100];
// Функция: типы параметров + тип возвращаемого значения
function add(a: number, b: number): number {
return a + b;
}
// void: функция не имеет возвращаемого значения
function log(msg: string): void {
console.log(msg);
}
// Необязательный параметр: добавьте ? после имени параметра
function greet(name: string, title?: string): string {
return title ? `${title} ${name}` : name;
}
console.log(greet("EXAMPLE")); // Вывод: EXAMPLE
console.log(greet("example", "Mr.")); // Вывод: Mr. example
Интерфейс
Интерфейс используется для описания «формы» объекта, определяя, какие свойства и методы должны быть у объекта.
Пример
interface User {
id: number; // Обязательно
name: string; // Обязательно
email?: string; // Необязательно, помечается знаком ?
readonly role: string; // Только для чтения, нельзя изменить после присваивания
}
// Параметр функции использует тип интерфейса
function printUser(user: User): void {
console.log(`ID: ${user.id}, Name: ${user.name}`);
if (user.email) {
console.log(`Email: ${user.email}`);
}
}
const admin: User = {
id: 1,
name: "EXAMPLE",
email: "[email protected]",
role: "admin",
};
printUser(admin);
// Вывод: ID: 1, Имя: EXAMPLE
// Вывод: Эл. почта: [email protected]
// admin.role = "user"; // Ошибка: невозможно присвоить 'role', так как это свойство доступно только для чтения.
// Наследование интерфейсов
interface AdminUser extends User {
permissions: string[];
}
Псевдоним типа
Псевдонимы типов используют ключевое словоtypeдля создания и могут определять псевдонимы для любого типа, включая сложные структуры, такие как объединённые типы и типы пересечения.
Пример
type ID = string | number;
let userId: ID = "abc-123"; // Допустимо
userId = 456; // Также допустимо
// Литеральный тип: ограничивает переменную конкретными значениями
type Direction = "up" | "down" | "left" | "right";
type Status = "pending" | "active" | "inactive";
function move(dir: Direction): void {
console.log(`Moving ${dir}`);
}
move("up"); // Верно
// move("diagonal"); // Ошибка: не входит в диапазон литерала
// Тип пересечения: объединяет несколько типов
type WithTimestamp = {
createdAt: Date;
updatedAt: Date;
};
type UserRecord = User & WithTimestamp; // Имеет все свойства как User, так и WithTimestamp
// Псевдоним типа функции
type Transformer<T, U> = (input: T) => U;
const toNumber: Transformer<string, number> = (s) => parseInt(s, 10);
Обобщения
Дженерики позволяют писать переиспользуемые компоненты, сохраняя типобезопасность. Можно думать о дженериках как о "переменных типа" — передавайте конкретные типы при их использовании.
Пример
function firstNumber(arr: number[]): number {
return arr[0];
}
// Использование дженериков: T — это параметр типа, конкретный тип определяется во время вызова
function first<T>(arr: T[]): T {
return arr[0];
}
const n = first<number>([1, 2, 3]); // n имеет тип number
const s = first<string>(["a", "b"]); // s имеет тип string
const inferred = first([true, false]); // TypeScript автоматически выводит T как boolean
// Обобщённый интерфейс
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
// Использование обобщённого интерфейса
const userResponse: ApiResponse<User> = {
data: { id: 1, name: "EXAMPLE", role: "admin" },
status: 200,
message: "success",
};
// Обобщённое ограничение: T должен иметь свойство id
function getById<T extends { id: number }>(items: T[], id: number): T | undefined {
return items.find(item => item.id === id);
}
Перечисления
Перечисления используются для определения набора именованных констант, делая "магические числа" или "магические строки" в коде осмысленными.
Пример
enum Direction {
Вверх, // 0
Down, // 1
По левому краю, // 2
Вправо, // 3
}
console.log(Direction.Up); // Вывод: 0
console.log(Direction[0]); // Вывод: "Up" (обратное сопоставление)
// Строковое перечисление (рекомендуется, значения более удобочитаемы при отладке)
enum Color {
Red = "RED",
Green = "GREEN",
Blue = "BLUE",
}
function paint(color: Color): void {
console.log(`Рисование в ${color}`);
}
paint(Color.Red); // Вывод: Рисование в RED
// paint("red"); // Ошибка: строка "red" не имеет типа Color
// const enum: встраивается после компиляции, снижая накладные расходы во время выполнения
const enum HttpStatus {
ОК = 200,
NotFound = 404,
InternalError = 500,
}
const status: HttpStatus = HttpStatus.OK; // После компиляции напрямую заменяется числом 200
Вывод типов
TypeScript не требует вручную аннотировать типы для каждой переменной; компилятор автоматически выводит их на основе присвоенного значения.
Пример
let count = 0; // Выводится как number
let name = "EXAMPLE"; // Выводится как string
let flag = true; // Выводится как boolean
// Выведенный тип элемента массива
let numbers = [1, 2, 3]; // Выводится как number[]
// Вывод типа возвращаемого значения функции
function double(n: number) { // Тип возвращаемого значения автоматически выводится как number
return n * 2;
}
// Вывод типа объектного литерала
const config = {
host: "localhost", // string
port: 3000, // number
debug: false, // boolean
};
// config.port = "3000"; // Ошибка: тип 'string' не может быть присвоен типу 'number'.
Практический совет: параметрам функции обычно нужны явные аннотации типов (потому что вызывающий код не может вывести типы из значений параметров), тогда как локальные переменные и возвращаемые значения внутри тела функции в основном могут полагаться на выведение типов — не нужно вручную аннотировать всё.
Классы и модификаторы доступа
TypeScript полностью поддерживает синтаксис классов ES6 и добавляетpublic、private、protected、readonlyчетыре модификатора доступа.
Пример
readonly name: string; // Только для чтения, нельзя изменить после инициализации
private age: number; // Приватный, доступен только внутри класса
protected species: string; // Защищённый, доступен подклассам
constructor(name: string, age: number, species: string) {
this.name = name;
this.age = age;
this.species = species;
}
// публичный метод (по умолчанию public, можно опустить)
public introduce(): string {
return `IЯ ${this.name}, ${this.species}.`;
}
// геттер: вызвать метод, как при доступе к свойству
get info(): string {
return `${this.name} (${this.age} лет)`;
}
}
class Dog extends Animal {
private breed: string;
constructor(name: string, age: number, breed: string) {
super(name, age, "Canis lupus familiaris"); // Вызов конструктора родительского класса
this.breed = breed;
}
// Подкласс может обращаться к protected-свойствам
describe(): string {
return `${this.name} — это ${this.species}, порода: ${this.breed}`;
}
}
const dog = new Dog("ПРИМЕР", 3, "Лабрадор");
console.log(dog.introduce()); // Вывод: I'm EXAMPLE, a Canis lupus familiaris.
console.log(dog.info); // Вывод: EXAMPLE (3 года)
// console.log(dog.age); // Ошибка: к приватному свойству нельзя получить доступ извне
Декоратор
Декораторы — это синтаксис метапрограммирования, используемый для добавления дополнительного поведения классам, методам и свойствам; часто встречается в таких фреймворках, как Angular, NestJS и т. д.
TypeScript 5.0 реализовал декораторы как официальный стандарт (предложение Stage 3), так что больше не требуетсяexperimentalDecoratorsфлаг.
Пример
function sealed(constructor: Function) {
Object.seal(constructor); // Предотвращает добавление новых свойств
Object.seal(constructor.prototype);
}
// Декоратор метода: может использоваться для логирования, проверки прав доступа и т. д.
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Вызов ${propertyKey} с аргументами:`, args);
const result = original.apply(this, args);
console.log(`${propertyKey} вернул:`, result);
return result;
};
}
@sealed
class Calculator {
@log
add(a: number, b: number): number {
return a + b;
}
}
const calc = new Calculator();
calc.add(1, 2);
// Вывод: Вызов add с аргументами: [ 1, 2 ]
// Вывод: add вернул: 3
Области применения
Благодаря полной совместимости с JavaScript, TypeScript можно использовать почти везде, где работает JavaScript, и он приносит дополнительные преимущества в крупных проектах.
Фронтенд-разработка
Это наиболее широко используемый сценарий для TypeScript. Все три основных фронтенд-фреймворка обеспечивают первоклассную поддержку TypeScript:
| Фреймворк | Поддержка TypeScript | Типичный сценарий |
|---|---|---|
| Angular | Официальный язык, TypeScript по умолчанию, не избежать. | Корпоративные SPA, административные системы |
| React | Официально предоставляется@types/react, Create React App и Vite оба включают шаблоны TypeScript | Электронная коммерция, контент-платформы, административные/бэкенд-приложения |
| Vue | Исходный код ядра Vue 3 переписан на TypeScript, а Composition API значительно повышает удобство работы с TypeScript | Небольшие и средние проекты, постепенная миграция |
| Next.js / Nuxt | Встроенная поддержка TypeScript, включена по умолчанию для новых проектов | Полностековые SSR/SSG-приложения |
Разработка бэкенда на Node.js
TypeScript столь же распространён в разработке бэкенда на Node.js.NestJSВ настоящее время это самый популярный бэкенд-фреймворк на TypeScript, использующий модульную архитектуру, похожую на Angular, со встроенной поддержкой внедрения зависимостей и декораторов.
Кроме того,DenoСреда выполнения с самого начала нативно поддерживает TypeScript и может запускать его напрямую без какой-либо конфигурации..tsфайлы.BunТакже имеет встроенную поддержку TypeScript.
Инструменты и скрипты командной строки
С помощьюts-node、tsxи других инструментов код TypeScript можно выполнять напрямую без предварительной компиляции, что делает его идеальным для написания сборочных скриптов и инструментов CLI.
Мобильная разработка и кроссплатформенность
React NativeПолностью поддерживает TypeScript, и многие корпоративные мобильные приложения (такие как Microsoft Office mobile, Shopify и т. д.) используют этот технологический стек.ExpoШаблон нового проекта также по умолчанию основан на TypeScript.
Разработка игр и графика
Babylon.js(3D-движок Microsoft) полностью написан на TypeScript и рассматривает определения типов TypeScript как полноправные элементы первого класса.Phaserи другие 2D-игровые движки также предоставляют полные определения типов.
История разработки
Появление и развитие TypeScript тесно связаны с эволюцией экосистемы JavaScript, и каждый выпуск крупной версии обусловлен ясными инженерными потребностями.
Истоки (2010 - 2012)
История TypeScript началась с инженерной задачи внутри Microsoft: как сделать крупные проекты на JavaScript сопровождаемыми.
ДизайнерAnders Hejlsberg— легенда индустрии, главный архитектор C# и создатель Turbo Pascal и Delphi. Он начал проектировать этот язык около 2010 года, с основной целью внедрить статическую проверку типов, не нарушая совместимость с JavaScript.
Ещё одной предпосылкой к выпуску TypeScript от Microsoft стал выход Windows 8 — приложения можно было разрабатывать с использованием HTML + JavaScript, и Microsoft надеялась привлечь программистов .NET, поэтому многие особенности синтаксиса TypeScript были намеренно сделаны похожими на C# и .NET.
В октябре 2012 года TypeScript 0.8 был публично выпущен после примерно двух лет внутренней разработки в Microsoft.
Ранние версии (2013 - 2015)
| Время | Version | Важные события |
|---|---|---|
| 2013-06 | 0.9 | Официальный стабильный релиз, значительно улучшенная производительность, улучшенная интеграция с IDE |
| 2014-04 | 1.0 | Первый официальный стабильный выпуск, в котором появились классы, интерфейсы, модули и поддержка компиляции в стандартный JavaScript |
| 2014-07 | — | Исходный код компилятора TypeScript открыт, размещён на GitHub, принимаются вклады сообщества |
| 2015-04 | — | Microsoft выпускает Visual Studio Code с глубокой встроенной поддержкой TypeScript; эти два продукта дополняют друг друга |
| 2015-07 | 1.5 | Добавлена поддержка синтаксиса модулей ES6, декораторов (экспериментальных) и пространств имён |
Быстрый рост (2016 - 2019)
Этот этап стал критически важным периодом для выхода TypeScript из нишевого инструмента в мейнстрим, а главной движущей силой стали решения в экосистеме фреймворков.
| Время | Версия / Событие | Значимость вехи |
|---|---|---|
| 2016-09 | TypeScript 2.0 | Были введены non-nullable-типы (--strictNullChecks), одна из важнейших возможностей типобезопасности TypeScript; введены размеченные объединённые типы |
| 2016 | Выпущен Angular 2 | Команда Google Angular объявила о принятии TypeScript в качестве официального языка разработки, выведя TypeScript в центр общественного внимания |
| 2017 | Серия TypeScript 2.x | Последовательно были введены условные типы, сопоставленные типы и ключевое слово infer, что значительно повысило выразительность системы типов |
| 2018-07 | TypeScript 3.0 | Project References, поддерживающие большие монорепозитории; был введён тип unknown (более безопасный верхний тип, чем any) |
| 2019 | DefinitelyTyped | Сопровождаемый сообществом репозиторий определений типов DefinitelyTyped (@types/*) охватывает более 7,000 пакетов, практически покрывая все основные npm-библиотеки |
Зрелость и внедрение (2020 - 2022)
| Время | Версия / Событие | Важный контент |
|---|---|---|
| 2020-08 | TypeScript 4.0 | Вариативные кортежные типы, помеченные элементы кортежей; значительно улучшенный опыт работы в редакторе |
| 2021 | Серия TypeScript 4.x | Типы литералов шаблонов, улучшенные встроенные служебные типы,noImplicitOverrideи другие улучшения строгого режима |
| 2022 | Опрос State of JS | Уровень использования TypeScript впервые превзошёл чистый JavaScript, став самым популярным языком-надмножеством в экосистеме JS |
| 2022 | Внедрение Vue 3 / Vite | Ядро Vue 3 переписано на TypeScript; в сочетании с Vite это выводит опыт работы с TypeScript во фронтенд-разработке на новый уровень |
Современная эпоха (2023 — настоящее время)
| Время | Version | Ключевые особенности |
|---|---|---|
| 2023-03 | TypeScript 5.0 | Современные декораторы (стандарт Stage 3), параметры типа const, все перечисления обновлены до union-перечислений, со значительными улучшениями производительности |
| 2023-08 | TypeScript 5.2 | Введено явное управление ресурсами (usingключевое слово), решая проблему детерминированной очистки таких ресурсов, как подключения к базам данных и файловые дескрипторы |
| 2024-03 | TypeScript 5.4 | Улучшено сужение типов в замыканиях,NoInferслужебные типы |
| 2024-06 | TypeScript 5.5 | вывод предикатов типа, проверка синтаксиса регулярных выражений, что позволяет системе типов точнее понимать логику кода |
| 2024-11 | TypeScript 5.7 | Поддержка--target es2024, более надёжное обнаружение неинициализированных переменных |
| 2025-03 | TypeScript 5.8 | Улучшенная проверка возвращаемых значений для условных типов и типов доступа по индексу; поддерживает при--module nodenextчерезrequire()загрузке ESM-модулей (требуется Node.js 22+) |
Перспективы на будущее: переписывание компилятора на Go
В начале 2025 года Microsoft объявила о важном решении: переписать компилятор TypeScript на Go, кодовое название проекта —Corsa。
В официальном заявлении говорится, что переписанный компилятор, как ожидается, обеспечит повышение производительности более чем в 10 раз, сократив время сборки крупных проектов с минут до секунд.
Согласно плану, версия на Go будет официально выпущена в TypeScript 7.x, тогда как текущие версии TypeScript 5.x / 6.x продолжат обычную итерацию и поддержку. Ожидается, что переписывание завершится к концу 2025 года.
Это переписывание не изменит синтаксис или систему типов самого языка TypeScript; для разработчиков это прозрачное обновление — ваш код не нуждается в изменениях, только скорость компиляции значительно повышается.
Сравнение TypeScript с другими статически типизированными языками
Если у вас есть опыт работы с другими строго типизированными языками, следующее сравнение поможет вам быстро понять философию дизайна TypeScript.
| Пункт сравнения | TypeScript | Java / C# | Go |
|---|---|---|---|
| Система типов | Структурная типизация (утиная типизация) | Номинальная типизация (необходимо явно объявлять отношения наследования) | Структурная типизация (неявные интерфейсы) |
| Null-безопасность | ВключениеstrictNullChecksподдерживает это в дальнейшем | Java требует аннотаций или Optional, C# 8+ поддерживает | Через значения ошибок и проверки на nil |
| Обобщения | Поддерживается, синтаксис похож на Java/C# | Поддерживается, в Java есть ограничения из-за стирания типов | Go 1.18+ поддерживает это, с более простым синтаксисом |
| Скомпилированный вывод | JavaScript (выполняется в JS-средах) | Байт-код (выполняется на JVM / CLR) | Нативный машинный код |
| Проверка типов во время выполнения | Нет (информация о типах стирается после компиляции) | Да (механизм рефлексии) | Отсутствует |
| Кривая обучения | Дружелюбен к JS-разработчикам, можно внедрять постепенно | Более сложен для новичков | Относительно прост, умеренная кривая обучения |
TypeScript используетсистему структурной типизации(Structural Typing): если два типа имеют одинаковую «форму», они считаются совместимыми, без необходимости явно объявлять отношения наследования. Это принципиально отличается от номинальной типизации Java/C# и также является ключевой причиной, по которой TypeScript может бесшовно взаимодействовать с JavaScript.
Ограничения TypeScript
TypeScript — не серебряная пуля; понимание его границ столь же важно.
| Ограничение | Описание | Как решить |
|---|---|---|
| Нет типов во время выполнения | Информация о типах полностью стирается после компиляции, и на типы нельзя полагаться при проверках во время выполнения | Используйте библиотеки, такие какzod、io-tsкогда требуется проверка во время выполнения |
| Этап компиляции | Добавляет этап компиляции по сравнению с чистым JS, увеличивая сложность проекта | Современные инструменты сборки (Vite, esbuild) уже хорошо с этим справляются |
| any как средство обхода проверки типов | Чрезмерное использованиеanyделает проверку типов неэффективной | ВключитьnoImplicitAnyиstrictрежим в сочетании с правилами ESLint |
| Барьер гимнастики типов | Сложные условные типы и mapped types не подходят для начинающих | Большинству бизнес-кода не нужны продвинутые типы; двигайтесь шаг за шагом |
| Поддержка сторонних библиотек | Несколько старых библиотек не имеют определений типов, и вам придётся самостоятельно писать .d.ts | Сначала проверьте,@types/*; если их действительно нет, напишите файл объявления вручную |