В чем разница между interface и type?
В TypeScript есть два похожих механизма для описания типов — interface и type. На первый взгляд они могут выполнять схожие задачи: определять структуру объектов, описывать сигнатуры функций и задавать алиасы для сложных конструкций. Однако у них есть различия в возможностях, области применения и некоторых технических деталях.
Общая идея
И interface, и type позволяют создавать новые типы данных. Разница заключается в том, что интерфейсы больше ориентированы на описание объектов и классов, то есть на определение контрактов, в то время как type более универсален и может использоваться для создания алиасов любых типов, включая примитивы, объединения и пересечения.
Основные особенности interface
Интерфейсы предназначены в первую очередь для описания структуры объектов и контрактов классов.
Пример:
interface User {
id: number;
name: string;
}
Особенности интерфейсов:
-
Могут расширять другие интерфейсы с помощью extends.
-
Классы могут реализовывать интерфейсы через implements.
-
Поддерживают декларативное расширение (один и тот же интерфейс можно объявить несколько раз, и они сольются).
Основные особенности type
type позволяет создавать алиасы для любых типов, а не только объектов.
Пример:
type User = {
id: number;
name: string;
};
Особенности type:
-
Можно описывать объединения (|) и пересечения (&).
-
Можно создавать алиасы для примитивов.
-
Нельзя расширять одним и тем же способом, как у интерфейсов, но можно комбинировать через &.
-
Не поддерживает декларативное расширение, как интерфейсы.
Возможности расширения
Интерфейсы поддерживают наследование через extends:
interface Person {
name: string;
}
interface Employee extends Person {
employeeId: number;
}
В type наследование реализуется через пересечение типов (&):
type Person = {
name: string;
};
type Employee = Person & {
employeeId: number;
};
Оба подхода дают схожий результат, но интерфейсы более читаемы при работе именно с объектами.
Декларативное расширение интерфейсов
Ключевое отличие интерфейсов от type — возможность их расширять декларативно. Если один и тот же интерфейс объявлен дважды, то компилятор объединит их.
interface Car {
brand: string;
}
interface Car {
year: number;
}
const myCar: Car = {
brand: "Toyota",
year: 2021
};
С type так сделать нельзя — повторное объявление приведет к ошибке.
Использование с классами
Интерфейсы изначально проектировались для того, чтобы их можно было использовать в связке с классами через implements. Это позволяет явно указать, какие свойства и методы класс обязан реализовать.
interface Logger {
log(message: string): void;
}
class ConsoleLogger implements Logger {
log(message: string) {
console.log(message);
}
}
С type можно описать аналогичную структуру, но его применение в связке с классами считается менее наглядным.
Поддержка примитивов и объединений
Интерфейсы ограничены объектными структурами и сигнатурами функций, тогда как type может описывать примитивные типы и объединения:
type ID = number | string;
type Status = "success" | "error" | "pending";
Такого интерфейс сделать не может.
Практическое применение
-
interface чаще выбирают, когда нужно описывать структуру объектов или контракты классов.
-
type применяют для объединений, алиасов примитивов, сложных комбинаций и работы с utility-типами.
Таким образом, в реальных проектах оба механизма используются в связке: интерфейсы для моделей данных и классов, а типы для сложных преобразований и объединений.