Интерфейсы и типы
TypeScript описывает данные через форму — набор имён и типов свойств и методов, — а не через классовую иерархию, как номинальные языки. Форму объекта описывают два инструмента: interface и псевдоним типа type. Оба проверяются на этапе компиляции и полностью стираются в рантайме — в итоговом JavaScript нет ни интерфейсов, ни псевдонимов, только значения.
Ключевая идея, которую новичок часто упускает: совместимость типов в TypeScript структурная. Объект подходит типу, если у него есть нужные члены, — даже если он никогда не объявлял этот интерфейс по имени. Отсюда и «утиная» типизация, и особая проверка лишних свойств у свежих литералов, и то, что interface и type во многом взаимозаменяемы для форм объектов, но расходятся на слиянии объявлений, объединениях и вычисляемых типах. Полная карта — в слоях ниже.
Карта темы
- Интерфейсы — контракт формы объекта: свойства, методы,
?,readonly,implements,extends; почему интерфейс ничего не стоит в рантайме. - Псевдонимы типов (type) —
typeкак имя для любого типа; чемinterfaceотличается отtype— слияние, объединения, способы расширения и их компромиссы. - Структурная типизация — совместимость по форме, «утиная» типизация и ⚠️ проверка лишних свойств у объектных литералов.
- Индексные сигнатуры —
[key: string]: Tдля открытого набора ключей и чем это отличается отRecord<K, V>.
Частые ошибки и ловушки
| Ошибка | Последствие | |
|---|---|---|
Думать, что interface существует в рантайме | Интерфейс полностью стирается при компиляции; его нельзя прочитать через typeof во время выполнения | |
Путать interface с классом | У интерфейса нет тел методов и конструктора; к нему нельзя применить new | |
Считать interface и type полными синонимами | Только type выражает объединения, кортежи и вычисляемые типы; только interface умеет слияние объявлений | |
| Ждать проверку лишних свойств при любом присваивании | Проверка на лишние свойства бьёт только по свежим объектным литералам, а не по переменным | |
| Использовать индексную сигнатуру там, где нужен фиксированный набор ключей | { [k: string]: V } открыт любому ключу; `Record<'a' \ | 'b', V>` требует ровно эти ключи |
| Считать повторное имя интерфейса ошибкой дублирования | Одноимённые интерфейсы сливаются; а вот повторный type того же имени — ошибка |
Значение для собеседований
Интерфейсы и типы спрашивают почти на любом TypeScript-интервью — но проверяют не синтаксис, а модель системы типов. Кандидат, который объясняет, что типы стираются, а совместимость структурная, сразу выделяется на фоне «ну, это как в Java, только контракт».
Что обычно проверяют:
- Что описывает
interfaceи почему он не стоит ничего в рантайме. - Когда брать
interface, а когдаtype, и что умеет только один из них. - Что такое структурная типизация и почему свежий литерал с лишним полем даёт ошибку, а переменная — нет.
- Чем
Record<K, V>отличается от индексной сигнатуры и когда каждый уместен. - Что такое слияние объявлений и зачем оно нужно (например, дополнить
Window).
Типичный неверный ответ: «interface и type — это одно и то же». Это открывает разговор о том, что для форм объектов они почти взаимозаменяемы, но type умеет объединения и вычисляемые типы, а interface — слияние объявлений, и что выбор влияет на расширяемость публичного API.