Бесплатный курс по TypeScript. Зарегистрируйтесь для отслеживания прогресса →

TypeScript: Использование интерфейсов

В этом уроке мы разберем использование интерфейсов. В предыдущем уроке мы рассказывали, что их работа похожа на работу типов в TypeScript. Но у них есть и свои особенности, которые мы затронем сегодня.

Расширение интерфейса дополнительными полями

Если интерфейс необходимо расширить дополнительными полями после его инициализации, мы можем повторно объявить интерфейс с новыми свойствами. Такой способ называется слиянием деклараций:

interface IUser {
  rating: number;
}

interface IUser {
  nickname: string;
  birthdate: number;
}

const sergey: IUser = {
  nickname: 'Sergey',
  birthdate: 1990,
  rating: 1102,
}

Здесь мы создали интерфейс IUser, а затем для демонстрационных целей расширили его новыми свойствами. После этого создали на его основе объект Sergey.

Рассмотрим другой способ работы с интерфейсом.

Расширение интерфейса с помощью другого интерфейса

Мы можем расширить интерфейс с помощью создания другого интерфейса, который наследуется от него:

interface IStudent extends IUser {
  group: number;
}

const sergey: IStudent = {
  nickname: 'Sergey',
  birthdate: 1990,
  rating: 1102,
  group: 2,
}

В этом примере мы создали на основе нашего предыдущего интерфейса IUser еще один — IStudent, в который добавили свойство group. Так интерфейс IStudent имеет все свойства IUser и все свойства, которые мы указали при его расширении от IUser, то есть дополнительно group.

Теперь рассмотрим, как работать с несколькими интерфейсами.

Расширение нескольких интерфейсов

Еще интерфейсы могут расширять сразу несколько других интерфейсов:

interface IUser {
  nickname: string;
  rating: number;
}

interface IEditor {
  courses: [string];
  canEdit: boolean;
}

interface IAuthor extends IUser, IEditor {
  team: string;
}

const sergey: IAuthor = {
  nickname: 'Sergey',
  rating: 20,
  courses: ['typescript'],
  canEdit: true,
  team: 'Hexlet College'
}

В примере выше мы создали экземпляр на основе интерфейса IAuthor, который был создан путем расширения интерфейсов IUser и IEditor. Этот экземпляр взял в себя все свойства данных интерфейсов и свойство, которое мы указали при создании самого интерфейса IAuthor.

Создание intersection types

Также TypeScript позволяет нам создавать перекрестные типы (intersection types) из нескольких интерфейсов c помощью литерала &:

interface IOneWay {
  one: string;
}

interface IOrAnother {
  another: string;
}

type OneWayOrAnother = IOneWay & IOrAnother;

const example: OneWayOrAnother = {
  one: 'A',
  another: 'B',
}

Здесь мы создали тип OneWayOrAnother на основе двух интерфейсов при помощи литерала &. Данный тип включил в себя все свойства указанных интерфейсов.

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

Может случиться так, что мы не знаем заранее всех свойств, которые будут содержаться в нашем интерфейсе. Но нам известно их возможное содержание. В таком случае удобно использовать специальную индексную сигнатуру, которая позволяет описать типы возможных значений:

interface IPhoneBook {
  [index:string]: number;
}

const myNotePad: IPhoneBook = {
  ivan: 55531311,
  sergey: 55500110,
  mom: 55522111,
}

В примере выше мы решили вопрос создания телефонной книги с помощью индексной сигнатуры. Это позволило нам не указывать множество свойств с именами, но лишь один раз указать тип ключа и тип его значения.

Выводы

Интерфейсы — это еще один мощный инструмент в TypeScript наряду с типами. Он позволяет гибко описать наши данные. Также он удобно поддается расширению и объединению с другими типами или интерфейсами.

Задание

Вам даны несколько интерфейсов. На их основе создайте интерфейс ISuperman. ISuperMan должен иметь метод guessWho, принимающий и возвращающий строку.

На основе интерфейса ISuperMan создайте объект superMan. Метод guessWho должен работать следующим образом: если в качестве строки в аргументе приходит любое значение кроме superman (в любом регистре), то следует вернуть предположение "It's a ${value}?", иначе "It's a ${value}!".

console.log(superMan.guessWho('bird')); // "It's a bird?";
console.log(superMan.guessWho('plane')); "It's a plane?";
console.log(superMan.guessWho('superman')); "It's a superman!";
Упражнение не проходит проверку — что делать? 😶

Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

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

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

Мой код отличается от решения учителя 🤔

Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.

В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.

Прочитал урок — ничего не понятно 🙄

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.

Полезное


Нашли ошибку? Есть что добавить? Пулреквесты приветствуются https://github.com/hexlet-basics
Если вы столкнулись с трудностями и не знаете, что делать, задайте вопрос в нашем большом и дружном сообществе