Аннотация типов
После имени переменной через двоеточие указывается тип:
const age: number = 25;
const userName: string = "Анна";
const isActive: boolean = true;
Выведение типов (type inference)
Если тип не указан, TypeScript выводит его сам по значению. Эти два варианта эквивалентны:
const age: number = 25;
const age = 25; // TypeScript сам понял, что number
Правило: для локальных переменных тип можно не писать (выведение сработает), а для параметров функций, возвращаемых значений и публичных API — лучше указывать явно, чтобы контракт был виден другим разработчикам.
Примитивные типы
number
Все числа — и целые, и с плавающей точкой, и специальные форматы. Раздельных
int/float нет:
const integer: number = 42;
const float: number = 3.14;
const hex: number = 0xff; // 255, шестнадцатеричное
const binary: number = 0b1010; // 10, двоичное
const octal: number = 0o744; // 484, восьмеричное
string
Строки — в одинарных, двойных кавычках или в виде шаблонной строки (с подстановкой переменных):
const single: string = 'Привет';
const double: string = "Мир";
const name: string = "Анна";
const age: number = 28;
// Шаблонная строка — обратные кавычки и ${...}
const greeting: string = `Привет, ${name}! Тебе ${age} лет.`;
boolean
Только два значения — true и false. Часто
получается как результат сравнения:
const isActive: boolean = true;
const hasAccess: boolean = age >= 18;
Массивы
Два равнозначных способа объявить массив чисел:
const numbers: number[] = [1, 2, 3];
const moreNumbers: Array<number> = [4, 5, 6];
Реальный пример — массив пользователей:
const users: string[] = ["Анна", "Борис", "Вера"];
// Методы массива сохраняют тип элемента
const upper: string[] = users.map((u) => u.toUpperCase());
const adults: string[] = users.filter((u) => u.length > 3);
Компилятор не даст положить в массив число чужого типа:
const prices: number[] = [100, 200];
prices.push("триста");
// ^^^^^^^^
// Ошибка: аргумент типа "string" не присваивается "number"
Многомерные массивы
const matrix: number[][] = [
[1, 2, 3],
[4, 5, 6],
];
readonly-массивы
Если массив нельзя менять — используйте readonly:
const weekdays: readonly string[] = ["Пн", "Вт", "Ср"];
// weekdays.push("Чт"); // Ошибка: push отсутствует у readonly string[]
Кортежи (tuple)
Массив фиксированной длины с известными типами в каждой позиции. Удобен для возврата нескольких значений из функции:
const pair: [string, number] = ["Анна", 28];
const name = pair[0]; // string
const age = pair[1]; // number
// pair[2]; // Ошибка: кортеж длиной 2
Реальный кейс — результат с флагом успеха:
function tryParse(value: string): [boolean, number] {
const parsed = Number(value);
return [Number.isFinite(parsed) && value.trim() !== "", parsed];
}
const [ok, num] = tryParse("42");
if (ok) {
console.log(num * 2);
}
Enum (перечисления)
Именованный набор констант. Удобен для фиксированного набора значений, например статусов заказа:
enum OrderStatus {
New = "new",
Paid = "paid",
Shipped = "shipped",
Done = "done",
}
const status: OrderStatus = OrderStatus.Paid;
if (status === OrderStatus.Paid) {
console.log("Можно отправлять");
}
Альтернатива без enum — объединение строковых литералов
(легче компилируется, рекомендуется в современных проектах):
type OrderStatus = "new" | "paid" | "shipped" | "done";
const status: OrderStatus = "paid";
any и unknown
any — отключение проверок
any — это «выключить TypeScript для этой переменной». Любая
операция разрешена:
let value: any = 10;
value = "текст"; // ОК
value.toUpperCase(); // ОК для TS, но упадёт в рантайме, если value — число
value.nonexistent.prop; // ОК для TS, но упадёт
Использовать any стоит только как временную меру при миграции
JS → TS. В новом коде его быть не должно.
unknown — безопасная альтернатива
unknown — «мы не знаем тип». В отличие от any,
перед использованием значение нужно проверить:
let input: unknown = JSON.parse('{"x":1}');
// input.x; // Ошибка: unknown не имеет свойств
// Безопасное использование — после проверки
if (typeof input === "object" && input !== null && "x" in input) {
console.log("Объект с полем x");
}
Главное правило: данные «снаружи» (API, localStorage, JSON) типизируйте как
unknown и проверяйте, а не как any.
null и undefined
В строгом режиме (strictNullChecks) эти типы несовместимы с
другими — это защищает от частого класса ошибок:
const name: string = null;
// ^^^^
// Ошибка: тип "null" нельзя присвоить типу "string"
// Если значение может отсутствовать — объединение:
const name: string | null = null;
const age: number | undefined = undefined;
Для безопасного доступа к свойствам есть операторы ?.
(optional chaining) и ?? (nullish coalescing):
interface User {
name: string;
address?: { city: string };
}
const user: User | null = getUser();
// Старый способ — длинно
const city = user && user.address ? user.address.city : "неизвестно";
// Современный — короткий
const city = user?.address?.city ?? "неизвестно";
void и never
void — функция ничего не возвращает (например,
console.log):
function log(message: string): void {
console.log(message);
}
never — функция никогда не завершается нормально (бросает
исключение или зацикливается):
function fail(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
Кейс из реального проекта: типизация ответа API
Представим обработку списка товаров из бэкенда:
// Без типов — любая ошибка всплывёт только в продакшене
function renderProducts(response) {
response.products.forEach((p) => addToCart(p.id, p.price));
}
// renderProducts({ items: [] }); // тихо упадёт: products !== items
// С типами — ошибка видна сразу
interface Product {
id: number;
title: string;
price: number;
}
interface ProductsResponse {
products: Product[];
total: number;
}
function renderProducts(response: ProductsResponse): void {
response.products.forEach((p) => addToCart(p.id, p.price));
// ^^^^^ Тип Product, у него есть id и price
}
// renderProducts({ items: [] });
// Ошибка: отсутствует обязательное свойство "products"
Типичные ошибки
1. Указание типа там, где он и так выводится
// Лишнее
const age: number = 25;
// Достаточно
const age = 25;
2. Забыли null/undefined
function getName(): string {
return localStorage.getItem("name");
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Ошибка: getItem возвращает string | null
}
3. Смешение типов в массиве без union
const mixed = [1, "два", true]; // (string | number | boolean)[]
mixed.push({}); // Ошибка: объект не входит в объединение
Практика
- Объявите массив цен
number[]и посчитайте сумму черезreduce. - Опишите функцию
formatPrice(amount: number): string, возвращающую строку вида"100 ₽". - Напишите функцию
safeParse(value: unknown): number | null, которая возвращает число, еслиvalue— число или строка-число, иначеnull. - Объявите кортеж
[string, number, boolean]для хранения пароля, длины и флага валидности.
Итог
Мы разобрали примитивные типы (number, string,
boolean), массивы, кортежи, перечисления, безопасный
unknown против опасного any, обработку
null/undefined и служебные типы void
и never. В следующей главе — как описывать форму объектов через
интерфейсы и type.
Комментарии 0
Пока нет комментариев. Станьте первым!