Type vs Interface в TypeScript — выбор и различия
-
TypeScript предоставляет два мощных механизма для определения типов: type и interface. Оба позволяют создавать типы, которые описывают структуры объектов, функций и других данных. Однако между ними существуют тонкие различия, которые могут повлиять на выбор инструмента в зависимости от задачи. Давайте разберемся, чем они отличаются и когда что использовать.
Что такое type и interface?
type (тип)
Ключевое слово type создает алиас (псевдоним) для существующего типа или определяет новый тип через комбинацию других типов. Например:
type Name = string; type Coordinates = { x: number; y: number };
interface (интерфейс)
Интерфейс описывает форму объекта, включая его свойства и методы. Интерфейсы могут быть расширены или реализованы классами:
interface User { name: string; age: number; }
Ключевые различия между type и interface
Расширение типов
- interface : Поддерживает множественное наследование через
extends
.
interface Animal { name: string; } interface Dog extends Animal { breed: string; }
- type : Использует оператор
&
(пересечение типов) для комбинации.
type Animal = { name: string; }; type Dog = Animal & { breed: string; };
Union и Intersection Types
- type : Позволяет создавать объединения (
|
) и пересечения (&
) типов.
type ID = string | number; // Union type type ButtonProps = BaseProps & { color: string }; // Intersection type
- interface : Не поддерживает объединения напрямую. Может расширять несколько интерфейсов, но не примитивы или другие типы.
Declaration Merging (Объединение объявлений)
- interface : Поддерживает декларативное объединение . Если несколько интерфейсов с одинаковым именем, TypeScript автоматически объединит их:
interface User { name: string; } interface User { age: number; } const user: User = { name: "Alice", age: 30 }; // Работает!
- type : Не позволяет повторно объявлять одно и то же имя:
type User = { name: string }; type User = { age: number }; // ❌ Ошибка: Имя "User" уже объявлено.
Использование с примитивами
- type : Может создавать псевдонимы для примитивов:
type Score = number;
- interface : Не может заменять примитивы.
Реализация в классах
- interface : Может быть реализован классом через
implements
:
class Person implements User { name: string; }
- type : Обычные типы-объекты также поддерживают implements, но union-типы — нет:
type User = { name: string }; class Person implements User { /* Работает */ } type ID = string | number; class Entity implements ID { /* ❌ Ошибка */ }
Когда что использовать?
Используйте interface, если:
- Вам нужна поддержка декларативного объединения (например, для расширения библиотечных типов).
- Вы работаете с классами , реализующими интерфейс.
- Требуется наследование нескольких интерфейсов.
Используйте type, если:
- Нужны union-типы (
|
) или intersection-типы (&
). - Вы создаете псевдоним для примитива, сложного типа или функции:
type Callback = (error: Error | null, data: string) => void;
- Вы предпочитаете иммутабельность типов (избегаете случайного изменения через повторные объявления).
Примеры из практики
Union Types (только type)
type Theme = "light" | "dark"; function setTheme(theme: Theme) { /* ... */ }
Расширение интерфейсов
interface FormProps { onSubmit: () => void; } interface LoginFormProps extends FormProps { username: string; }
Декларативное объединение
interface Window { myPlugin: PluginAPI; } // В другом файле: interface Window { myPlugin: PluginAPI; // Расширение существующего интерфейса }
Заключение
Выбор между type и interface часто зависит от контекста и предпочтений команды. Вот краткий чек-лист:
- Для объектных структур и наследования — interface.
- Для union/intersection типов , псевдонимов и функциональных типов — type.
Оба подхода дополняют друг друга, и их совместное использование позволяет писать гибкий и типобезопасный код. Главное — соблюдать консистентность в проекте и документировать принятые стандарты.
Дополнительные ресурсы:
- interface : Поддерживает множественное наследование через
© 2024 - 2025 RosDesk, Inc. Все права защищены.