Объекты и простые интерфейсы

Урок: Объекты и простые интерфейсы в TypeScript

Введение

До этого момента мы работали с простыми данными:

  • строками (string);
  • числами (number);
  • булевыми значениями (boolean);
  • функциями.

Но в реальной разработке почти всегда приходится работать не с отдельными значениями, а с наборами данных.

Например:

  • пользователь (имя, возраст, email);
  • товар (название, цена, наличие);
  • настройки (флаги, параметры).

В JavaScript для этого используются объекты. Но без типизации они могут быть непредсказуемыми.

TypeScript решает эту проблему — он позволяет описывать структуру объектов.

Главная идея урока: мы учимся описывать форму объектов и делать их предсказуемыми с помощью типов и интерфейсов.


Типизация объектов напрямую

Начнём с простого объекта.

const user: { name: string; age: number } = {
  name: 'Alex',
  age: 30,
};

Что здесь происходит:

  • мы явно описали структуру объекта;
  • name должен быть строкой;
  • age — числом.

Если попытаться сделать ошибку, TypeScript подсветит её до запуска:

// const badUser: { name: string; age: number } = {
//   name: 'Alex',
//   age: '30', // ошибка TS: age должен быть number
// };
const user: { name: string; age: number } = { name: 'Alex', age: 30 };
console.log('корректный пользователь:', user.name, user.age);

Почему такой способ неудобен

На первый взгляд всё работает, но есть проблема.

Если у тебя много объектов с одинаковой структурой:

const user1: { name: string; age: number } = { name: 'Alex', age: 30 };
const user2: { name: string; age: number } = { name: 'Bob', age: 25 };

Ты начинаешь:

  • повторять один и тот же тип;
  • усложнять код;
  • увеличивать шанс ошибки.

Здесь и появляются интерфейсы.


Что такое интерфейс

Интерфейс — это способ задать «шаблон» для объекта.

interface User {
  name: string;
  age: number;
}

console.log(
  'Интерфейс существует только на этапе проверки TS; в рантайме остаётся обычный объект с полями name и age.',
);

Теперь можно использовать его:

interface User {
  name: string;
  age: number;
}

const user: User = {
  name: 'Alex',
  age: 30,
};
console.log(user.name, user.age);

Что изменилось:

  • структура описана один раз;
  • код стал чище;
  • легче поддерживать.

Как работает интерфейс

Интерфейс не создаёт объект. Он только описывает, каким должен быть объект.

TypeScript проверяет:

  • есть ли все нужные поля;
  • совпадают ли типы.

Пример ошибки (в реальном файле такой объект не пройдёт проверку):

interface User {
  name: string;
  age: number;
}

// const user: User = {
//   name: 'Alex',
//   // age отсутствует — ошибка TS
// };

const user: User = { name: 'Alex', age: 30 };
console.log('обязательные поля заполнены:', user);

Или неверный тип поля:

interface User {
  name: string;
  age: number;
}

// const user: User = {
//   name: 'Alex',
//   age: '30', // ошибка TS: age — number
// };

const user: User = { name: 'Alex', age: 30 };
console.log('age — число:', user.age);

Дополнительные свойства объекта

TypeScript строго проверяет структуру.

interface User {
  name: string;
  age: number;
}

// const user: User = {
//   name: 'Alex',
//   age: 30,
//   isAdmin: true, // ошибка TS: лишнее поле при явном типе User
// };

const user: User = { name: 'Alex', age: 30 };
console.log('только поля из интерфейса:', user);

Почему это важно:

  • предотвращает случайные ошибки;
  • не даёт «засорять» объект лишними данными.

Необязательные свойства

Иногда не все поля обязательны.

Например:

  • у пользователя может быть email, а может и не быть.

Для этого используется ?.

interface User {
  name: string;
  age: number;
  email?: string;
}

const withEmail: User = { name: 'Bob', age: 25, email: 'bob@example.com' };
const withoutEmail: User = { name: 'Alex', age: 30 };
console.log('с email:', withEmail.email, '| без email:', withoutEmail.email);

Теперь:

interface User {
  name: string;
  age: number;
  email?: string;
}

const user1: User = {
  name: 'Alex',
  age: 30,
};
const user2: User = {
  name: 'Bob',
  age: 25,
  email: 'bob@example.com',
};
console.log(user1.name, user2.email);

Поле email:

  • может быть;
  • может отсутствовать;
  • но если есть — должно быть строкой.

Использование объектов в функциях

Интерфейсы особенно полезны в функциях.

interface User {
  name: string;
  age: number;
}

function printUser(user: User) {
  console.log(user.name + ' is ' + user.age);
}

printUser({ name: 'Alex', age: 30 });
// printUser({ name: 'Alex' }); // ошибка TS: не хватает age

TypeScript контролирует структуру переданных данных.


Вложенные объекты (базовое понимание)

Объекты могут содержать другие объекты.

Пример использования:

interface Address {
  city: string;
}

interface UserWithAddress {
  name: string;
  address: Address;
}

const user: UserWithAddress = {
  name: 'Alex',
  address: {
    city: 'Helsinki',
  },
};
console.log(user.address.city);

TypeScript проверяет структуру на всех уровнях.


Связь с дальнейшими уроками

Этот урок — очень важный шаг.

Мы перешли от:

  • отдельных значений к
  • структурированным данным.

Дальше мы:

  • научимся точно задавать, что возвращают функции;
  • будем использовать интерфейсы вместе с функциями;
  • применим это в Playwright (page, locator, test);
  • и в итоге — в Page Object.

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

Интерфейсы используются почти везде:

  • данные пользователя;
  • ответы API;
  • настройки;
  • структуры тестов.

Пример из реальной задачи:

interface LoginPayload {
  username: string;
}

function login(data: LoginPayload): void {
  console.log(data.username);
}

login({ username: 'admin' });

Это:

  • делает код понятным;
  • упрощает работу в команде;
  • снижает количество ошибок.

Итоговое понимание

Объекты — это способ хранить связанные данные. Интерфейсы — это способ сделать эти данные понятными и контролируемыми.

Главная идея урока:

TypeScript позволяет описать форму объекта один раз и затем использовать её везде, гарантируя, что данные всегда соответствуют ожиданиям.

Именно интерфейсы становятся основой для более сложных структур — включая Page Object, с которым мы будем работать дальше.