Хотите заказать веб-сайт? Связаться с нами

Анатомия типов в Typescript — аннотации, примитивы и литералы

В прошлых уроках мы установили TypeScript, научились его настраивать и поняли, зачем он нужен. Сегодня мы переходим к самому сердцу языка — его синтаксису. Я покажу вам, как с помощью аннотаций типов превратить ваш JavaScript-код в строго типизированный и предсказуемый.

TypeScript — это надстройка над JavaScript, и его синтаксис интуитивно понятен любому, кто уже знаком с JS. Главное нововведение — это возможность явно указывать типы данных для переменных, параметров функций и возвращаемых значений.

Анатомия типов в Typescript — аннотации, примитивы и литералы

Аннотации типов для переменных

Аннотация типа (краткое описание) ставится после имени переменной через двоеточие. Это ваш первый шаг к строгой типизации.

let username: string = "Alice";
let age: number = 30;
let isActive: boolean = true;
let id: number | string = "abc123"; // Union Type — об этом позже

Теперь, если вы попытаетесь присвоить переменной username число, TypeScript выдаст ошибку ещё до того, как код запустится:

username = 42; // ❌ Ошибка: Type 'number' is not assignable to type 'string'

Это называется строгой типизацией. В обычном JavaScript вы бы узнали об ошибке только во время выполнения, а TypeScript ловит её на этапе написания кода.

Примитивные типы: основа основ

TypeScript использует те же примитивные типы, что и JavaScript, но добавляет к ним строгость:

  1. number — любые числа: целые, дробные, отрицательные, Infinity, NaN.
  2. string — текстовые строки в одинарных, двойных или обратных кавычках.
  3. booleantrue или false.

null и undefined — тоже типы, но при включённом strictNullChecks (а мы его включили во втором уроке) вы не сможете просто так присвоить их переменным других типов.

let city: string = "Moscow";
city = null; // ❌ Ошибка при strictNullChecks

Литеральные типы: точность до значения

Более тонкая настройка — это литеральные типы. Они позволяют указать не просто «строка», а конкретную строку или конкретное число.

let status: "success" = "success"; // Только это значение
// status = "failure"; // ❌ Ошибка

let direction: "up" | "down" | "left" | "right"; // Union с литералами
direction = "up"; // ✅
direction = "north"; // ❌ Ошибка

Литеральные типы особенно полезны в комбинации с объединениями (Union Types), о которых мы поговорим в следующем уроке.

Аннотации для функций

Функции — это главное место, где аннотации типов приносят наибольшую пользу. Мы можем указать типы для каждого параметра и тип возвращаемого значения.

function greet(name: string): string {
  return `Hello, ${name}!`;
}

function add(a: number, b: number): number {
  return a + b;
}

function logMessage(message: string): void {
  console.log(message); // void означает, что функция ничего не возвращает
}

Почему это важно? Когда вы видите сигнатуру функции, вы сразу понимаете, как её использовать:

// Ясно и понятно
function calculateDiscount(price: number, percent: number): number {
  return price * (percent / 100);
}

// Вместо гаданий в JS
function calculateDiscount(price, percent) {
  return price * (percent / 100);
}

TypeScript также следит, чтобы вы не забыли вернуть значение (если обещали) и не вернули что-то не то:

function getMessage(): string {
  return 42; // ❌ Ошибка: Type 'number' is not assignable to type 'string'
}
Из ноутбука появляются летающие светящиеся экраны

Оживи свой сайт. Освой JavaScript!

Статичная верстка — это только скелет. Наш онлайн-курс "JavaScript с нуля до профи" даст твоим страницам мышцы и нервы. Научись создавать слайдеры, формы, интерактивные карты и получать данные с сервера.

От теории — к реальным скриптам в твоём портфолио.

Подробнее о курсе

Вывод типов (Type Inference)

Хорошая новость: вам не всегда нужно явно указывать типы. TypeScript умный и часто может вывести их сам.

let message = "Hello!"; // TypeScript выводит, что message — string
message = 42; // ❌ Ошибка: Type 'number' is not assignable to type 'string'
function multiply(a: number, b: number) {
  return a * b; // TypeScript выводит, что возвращается number
}

Однако есть случаи, когда TypeScript не может вывести тип — тогда переменная получает тип any (что отключает проверку). В строгом режиме это запрещено, и вы обязаны указать тип явно:

let data; // ❌ Неявный any (если включен noImplicitAny)
data = "hello";
data = 42; // Ошибки не будет, потому что any разрешает всё

Тип any и почему его стоит избегать

any — это способ сказать TypeScript «отстань от меня, я знаю, что делаю». Но на самом деле это лишает вас всех преимуществ TypeScript.

let value: any = "hello";
value = 42;
value = true;
value.someNonExistentMethod(); // ✅ Нет ошибки, но в рантайме всё упадёт

Если вы используете any, вы возвращаетесь к уровню безопасности обычного JavaScript. Вместо any лучше использовать unknown (если вы действительно не знаете тип) или уточнять типы с помощью Type Guards.

Практическое упражнение

Давайте закрепим материал. Вот несколько примеров кода на JavaScript. Ваша задача — добавить к ним аннотации типов, используя изученный синтаксис.

// 1. Переменные
const productName = "Laptop";
const productPrice = 999.99;
const inStock = true;

// 2. Функция
function formatPrice(price, currency) {
  return currency + price.toFixed(2);
}

// 3. Функция с разными типами параметров
function getLength(value) {
  return value.length;
}

// 4. Функция без возврата
function showMessage(text) {
  console.log(text);
}

Решение (не подглядывайте сразу):

// 1. Переменные
const productName: string = "Laptop";
const productPrice: number = 999.99;
const inStock: boolean = true;

// 2. Функция
function formatPrice(price: number, currency: string): string {
  return currency + price.toFixed(2);
}

// 3. Функция с разными типами параметров
function getLength(value: string | any[]): number {
  return value.length;
}

// 4. Функция без возврата
function showMessage(text: string): void {
  console.log(text);
}

Обратите внимание: в третьей функции мы использовали Union Type (string | any[]), потому что длина есть и у строк, и у массивов. Это одна из мощных возможностей TypeScript, к которой мы перейдём в следующем уроке.

Type Aliases: даём имена типам

Перед тем как закончить урок, я хочу познакомить вас с очень полезной концепцией — Type Aliases (псевдонимы типов). Они позволяют дать имя любому типу и переиспользовать его.

// Вместо того чтобы писать это каждый раз
let userId: string | number = 123;

// Мы создаём псевдоним
type ID = string | number;
let userId: ID = 123;
let productId: ID = "abc";

// Это работает и для более сложных типов
type Status = "active" | "inactive" | "pending";
let userStatus: Status = "active";

Псевдонимы типов особенно полезны, когда один и тот же тип используется в разных частях программы. Они делают код чище и уменьшают дублирование.

Итог

Сегодня мы заложили фундамент синтаксиса TypeScript:

  1. Аннотации типов для переменных, параметров и возвращаемых значений (: type).
  2. Примитивные типы — string, number, boolean, null, undefined.
  3. Литеральные типы — конкретные значения строк или чисел.
  4. Тип void для функций, которые ничего не возвращают.
  5. Вывод типов — TypeScript часто понимает типы сам, но не всегда.
  6. Псевдонимы типов (type) — даём имена сложным типам для переиспользования.

В следующем уроке мы углубимся в работу с массивами и объектами — структурами данных, с которыми вы работаете каждый день. Мы научимся описывать их форму и делать свойства опциональными. А затем перейдём к Union Types — мощному инструменту, который делает TypeScript по-настоящему гибким.

Теги: