Интерфейсы
Чему вы научитесь:
- описывать форму объекта через
interfaceи собирать новые формы черезextendsи&; - объяснять, почему TypeScript сравнивает типы по форме, а не по имени, и когда литерал с лишним свойством не проходит;
- описывать словарь индексной сигнатурой и помнить, что несуществующий ключ tsc не заметит;
- выбирать между
typeиinterface.

Представьте навесной замок. Внутри у него выемки, и он откроется, если зубцы ключа встанут ровно напротив них. Замку всё равно, какой фирмы ключ и что выбито на его головке: он проверяет только зубцы.
Объекты в TypeScript проверяются похоже. Функции, которая считает расстояние от точки до начала координат, неважно, откуда пришёл объект. Ей нужно одно: чтобы в нём были числа x и y. Раньше вы описывали такую форму через type. У TypeScript есть и второй способ, который часто встречается в чужом коде, — интерфейс: именованное описание формы объекта, его свойств и методов.
interface Point {
x: number;
y: number;
}
function distance(p: Point): number {
return Math.sqrt(p.x * p.x + p.y * p.y);
}
console.log(distance({ x: 3, y: 4 })); // 5Давайте разберём пример по строкам:
interface Point { … }объявляет интерфейсPoint: у объекта должны быть свойстваxиy, оба числа. Это и есть замок с двумя выемками.- Параметр
pполучает типPoint, поэтому внутри функции TypeScript знает, чтоp.xиp.y— числа. - Вызов передаёт литерал
{ x: 3, y: 4 }. Он подходит подPoint, и программа печатает5.
Как устроено объявление
Объявление интерфейса состоит из трёх частей:
- ключевое слово
interface; - имя с большой буквы:
Point,User,Order; - фигурные скобки со списком членов, где у каждого члена имя, двоеточие, тип и точка с запятой.
Сравните с псевдонимом типа. В записи type Point = { x: number; y: number }; после имени стоит знак =, а у интерфейса после имени сразу идут фигурные скобки. Проверяет компилятор оба способа одинаково: литерал без y в обоих случаях получит ошибку TS2741.
Интерфейс, как любой тип, существует только для компилятора. В JavaScript-файле, который запишет tsc, от него не останется ни строчки.
Что бывает внутри интерфейса
Посмотрим на интерфейс, где собраны все виды членов, которые встретятся в курсе чаще всего:
interface User {
readonly id: number;
name: string;
email?: string;
greet(): string;
}
const ann: User = {
id: 1,
name: "Ann",
greet() {
return `Hi, I am ${this.name}`;
},
};
console.log(ann.greet(), ann.email); // Hi, I am Ann undefinedОбычное свойство
name: string — свойство обязательно, и в нём лежит строка. Объект без name или с числом в name компилятор не пропустит. Так описывают всё, что есть у каждого пользователя.
Необязательное свойство
email?: string — свойство можно не указывать. Как и в type, читается оно как string | undefined. У ann почты нет, поэтому на месте ann.email программа печатает undefined. Знак ? ставят у того, что есть не у всех.
Свойство только для чтения
readonly id: number — значение задают при создании объекта, а записать потом ann.id = 2 tsc не даст: ошибка TS2540. Так помечают номера и всё, что после создания не меняется.
Метод
greet(): string — у объекта должен быть метод greet, который не принимает аргументов и возвращает строку. В интерфейсе пишут только имя метода, скобки с параметрами и тип результата, а тело метода — в самом объекте. Объект без greet не подойдёт: tsc сообщит, что свойства greet не хватает.
Внутри метода this — сам объект, поэтому this.name даёт "Ann", и программа печатает Hi, I am Ann undefined.
Здесь аналогия с замком перестаёт работать: у настоящего замка не бывает выемки «по желанию», а у интерфейса необязательные свойства бывают.
Частая ошибка
Интерфейс записали как псевдоним типа, со знаком =:
interface Point = { x: number; y: number }; // ✗error TS1005: '{' expected.Сообщение значит «ожидалась {»: после имени интерфейса компилятор ждёт фигурную скобку, а встречает =. Уберите знак =, и объявление станет верным: interface Point { x: number; y: number }.
Главное
interface Point { x: number; y: number }даёт имя форме объекта; знака=после имени нет.- Члены интерфейса — обычные свойства, необязательные (
?),readonly-свойства и методы вродеgreet(): string. - У метода в интерфейсе есть имя, параметры и тип результата, а тело пишут в объекте.
- Интерфейс, как любой тип, видит только компилятор: в JavaScript его нет.