В чем разница между interface и type в TypeScript и когда что использовать?
Основные различия между interface и type в TypeScript
Отличный вопрос! Действительно, на первый взгляд interface и type выглядят взаимозаменяемыми, но у них есть важные отличия. Давайте разберем их подробно.
1. Расширение (extends vs intersection)
interface использует ключевое слово extends для наследования:
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
// Dog: { name: string; breed: string; }
type использует оператор пересечения &:
type Animal = {
name: string;
}
type Dog = Animal & {
breed: string;
}
// Dog: { name: string; breed: string; }
2. Слияние объявлений (declaration merging)
Это ключевое отличие. interface можно объявлять несколько раз с одним именем — они автоматически объединятся:
interface User {
name: string;
}
interface User {
age: number;
}
// Результат: User = { name: string; age: number; }
type так делать нельзя — будет ошибка "Duplicate identifier".
3. Возможности type, которых нет у interface
type может представлять не только объекты, но и:
- Примитивные типы:
type ID = string | number; - Литеральные типы:
type Status = 'active' | 'inactive'; - Кортежи:
type Pair = [string, number]; - Условные типы:
type IsString<T> = T extends string ? true : false; - Mapped types:
type Readonly<T> = { readonly [K in keyof T]: T[K] };
4. Что умеет interface, но не умеет type?
Кроме слияния объявлений, interface может:
- Наследоваться от класса:
interface MyInterface extends MyClass { ... } - Использоваться в implements для классов:
class MyClass implements MyInterface { ... }
5. Производительность и компиляция
С точки зрения производительности компиляции, interface обычно быстрее, потому что TypeScript может кэшировать результаты. type с пересечениями (&) может быть медленнее на больших проектах из-за рекурсивной проверки типов.
6. Когда что использовать?
Используйте interface, когда:
- Вы определяете форму объекта (особенно для API/DTO)
- Вам нужно слияние объявлений (например, для расширения сторонних типов)
- Вы пишете библиотеку — interface лучше документируется
- Вы работаете с классами (implements)
Используйте type, когда:
- Вам нужны union/intersection типы
- Вы работаете с примитивами, кортежами или литералами
- Вам нужны условные или mapped типы
- Вы создаете вспомогательные типы-утилиты
Пример из практики
// Хорошо для interface
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
// Хорошо для type
type UserRole = 'admin' | 'user' | 'guest';
type ApiResult<T> = ApiResponse<T> | { error: string };
Итог
В 80% случаев для объектов можно использовать и то, и другое. Но если вы сомневаетесь — начинайте с interface, а переходите на type только когда нужны его специфические возможности. Это общепринятая практика в TypeScript-сообществе.
Дополнение: практический подход и производительность
Хочу добавить еще один важный аспект — производительность при разработке крупных проектов.
Проблема с type и пересечениями
Когда вы используете type с оператором & для объединения множества типов, TypeScript может создавать очень сложные структуры. Например:
type A = { a: string };
type B = { b: number };
type C = A & B & { c: boolean }; // Работает, но может быть медленно при вложенности
С каждым уровнем вложенности компилятору нужно рекурсивно проверять все свойства. В проектах с сотнями типов это может заметно замедлить работу IDE и компиляцию.
Как избежать проблем
- Для простых объектов используйте
interface— он быстрее и понятнее - Если вам нужно объединить 3+ типа, подумайте, не лучше ли создать отдельный интерфейс
- Для сложных условных типов используйте
type, но старайтесь не делать глубоких вложенностей
Еще один лайфхак
Иногда можно комбинировать оба подхода:
// Базовый интерфейс
interface BaseEntity {
id: number;
createdAt: Date;
}
// Тип для расширения
type UserEntity = BaseEntity & {
name: string;
email: string;
};
Так вы получаете преимущества интерфейса (читаемость, производительность) и гибкость типа (быстрое расширение).
Главное правило: не усложняйте там, где можно обойтись простым interface. TypeScript — это про читаемость и безопасность, а не про "магию" типов.