Learning Book

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

JavaScript: краткая предыстория

JavaScript создавался для коротких скриптов в браузере. Со временем он вырос в язык, на котором пишут приложения в сотни тысяч строк — и на клиенте, и на сервере (Node.js).

Но у JavaScript есть особенности, которые усложняют работу с большими кодовыми базами:

// Оператор == приводит типы — неожиданное поведение
if ("" == 0) {
  // true! Но почему?
}

// Обращение к несуществующему свойству не вызывает ошибку
const obj = { width: 10, height: 15 };
const area = obj.width * obj.heigth; // NaN, а не ошибка

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

Что такое TypeScript

TypeScript — это надмножество JavaScript со статической системой типов.

Это значит:

  • Любой валидный код на JavaScript — это валидный код на TypeScript
  • TypeScript добавляет аннотации типов — способ описать, какие значения ожидает функция или переменная
  • Компилятор проверяет типы до запуска программы и сообщает об ошибках
const obj = { width: 10, height: 15 };
// Ошибка: Property 'heigth' does not exist. Did you mean 'height'?
const area = obj.width * obj.heigth;

TypeScript нашёл опечатку ещё до того, как мы запустили код.

Статическая проверка типов

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

function fn(x) {
  return x.flip();
}
// TypeError: x.flip is not a function — только в рантайме

TypeScript — это статический анализатор типов. Он проверяет программу на ошибки до выполнения, основываясь на типах значений:

function greet(person: string, date: Date) {
  console.log(`Hello ${person}, today is ${date.toDateString()}!`);
}

// Ошибка: Expected 2 arguments, but got 1
greet("Brendan");

Ошибки, которые JavaScript не замечает

JavaScript не считает ошибкой обращение к несуществующему свойству — возвращает undefined. TypeScript считает это ошибкой:

const user = {
  name: "Daniel",
  age: 26,
};

// Ошибка: Property 'location' does not exist on type '{ name: string; age: number; }'
user.location;

TypeScript также ловит:

  • Опечатки в именах методов:
const announcement = "Hello World!";
// Ошибка: Did you mean 'toLocaleLowerCase'?
announcement.toLocaleLowercase();
  • Невызванные функции (забыли скобки):
function flipCoin() {
  // Ошибка: Math.random — это функция, а не число
  return Math.random < 0.5;
}
  • Логические ошибки (недостижимый код):
const value = Math.random() < 0.5 ? "a" : "b";
if (value !== "a") {
  // ...
} else if (value === "b") {
  // Ошибка: This comparison appears to be unintentional
  // because the types '"a"' and '"b"' have no overlap
}

Типы для инструментов

Статические типы нужны не только для поиска ошибок. Они дают IDE информацию для:

  • Автодополнения — редактор знает, какие свойства и методы доступны
  • Quick fixes — автоматическое исправление ошибок
  • Рефакторинга — безопасное переименование по всему проекту
  • Навигации — переход к определению, поиск всех использований

VS Code использует TypeScript «под капотом» даже для работы с обычными .js-файлами.

Структурная типизация

TypeScript использует структурную систему типов (duck typing): если два объекта имеют одинаковую форму, они совместимы по типу:

interface Point {
  x: number;
  y: number;
}

function logPoint(p: Point) {
  console.log(`${p.x}, ${p.y}`);
}

// point не объявлен как Point, но имеет нужную форму
const point = { x: 12, y: 26 };
logPoint(point); // OK — "12, 26"

Переменную point не нужно явно объявлять типом Point. Достаточно, чтобы у неё были свойства x и y с нужными типами.

Рантайм-поведение не меняется

TypeScript никогда не меняет поведение JavaScript-кода в рантайме. Если деление на ноль в JavaScript возвращает Infinity, то и после компиляции из TypeScript результат будет тем же.

Это гарантия: перенос кода с JS на TS не сломает его выполнение.

Итоги

АспектJavaScriptTypeScript
Проверка типовВ рантайме (typeof)До запуска (статически)
ОшибкиУзнаёте при выполненииВидите в редакторе
Система типовДинамическаяСтатическая, структурная
СовместимостьНадмножество JS
Рантайм-поведениеЭталонНе меняет JS-поведение