В чем разница между 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-типами.

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