
Вы могли заметить, что в TypeScript можно объявлять пользовательские типы двумя разными способами. Один с ключевым словом interface, а другой с ключевым словом type. Таким образом, вы можете задаться вопросом, почему есть два способа сделать одно и то же — и вы не одиноки. В своем руководстве по объявлению пользовательских типов в TypeScript я уже рассказывал, как вы можете использовать интерфейсы и типы, но давайте немного подробнее рассмотрим, чем они отличаются.
1. Синтаксис расширений интерфейсов отличается от типов
Если мы определяем тип в TypeScript, он не расширяется постфактум. Например, рассмотрим этот пользовательский тип, который я только что создал:
Если после того, как он был определен, я вдруг понимаю, что хочу добавить адрес, я могу сделать это, используя следующий синтаксис:
С интерфейсами мы можем сделать то же самое, но синтаксис остается немного другим:
Теперь userWithAddress содержит все свойства user плюс одно дополнительное свойство — address.
Единственная разница между этими двумя способами расширения типов заключается в том, как они обрабатывают конфликты. Например, если вы расширяете интерфейс и упоминаете свойство, которое уже было определено, будет выдана ошибка. Например, это не сработает:
Между тем, с type вы можете сделать это:
Хотя это не приведет к ошибке, это может привести к неожиданным результатам, поэтому вам следует избегать этого при необходимости. Например, выше свойство name сводится к типу never, поскольку тип never может быть и string, и number одновременно. :)
2. Интерфейсы можно объединять — типы нельзя
Точно так же types нельзя объединить, а interfaces можно, если вы объявите их несколько раз. Например, если у нас есть тип, мы не можем сделать что-то вроде этого:
На самом деле приведенный выше код вызовет ошибку. Между тем, с interface мы можем сделать это — и это объединит оба объявления. Таким образом, в приведенном ниже примере будет создан тип с именем cat со свойствами name и color:
3. Интерфейсы не могут расширять примитив
Хотя мы можем создать тип, который может быть псевдонимом примитивного типа, такого как string, interface не может этого сделать. Например, если вы хотите создать тип с именем myName, который всегда имеет строковый тип, мы можем сделать это следующим образом:
Здесь myName становится псевдонимом для string, так что мы можем писать myName вместо string, по сути, где угодно. Между тем, у interface нет этой способности. Следующее не может и не будет работать:
4. Типы могут создавать объединения, а интерфейсы — нет.
Мы можем создавать типы объединения с помощью ключевого слова type, но мы не можем сделать это с интерфейсом. Например, здесь userId может быть string или number:
Между тем, вышесказанное не может быть достигнуто с interface, так как интерфейс определяет форму или тип объекта.
5. Классы могут реализовывать интерфейсы, но не типы
Если вы используете классы в своем коде TypeScript, они могут реализовывать интерфейсы, но не типы. Это означает, что класс должен соответствовать самому интерфейсу. Если вы определяете type, вы не можете использовать его с классом. Например:
Это делает interface очень удобным, если вы решите использовать классы в своем коде TypeScript, но, как мы знаем, большая часть кода TypeScript имеет тенденцию быть функциональным, а не основанным на коде. Таким образом, это преимущество будет зависеть от вашей кодовой базы.
Заключение
Как видите, основные различия между type и interface зависят от обстоятельств, в которых вы их используете. Почти все функции interface доступны в type, а это значит, что вы можете чаще обращаться к type. Однако, как правило, это, как правило, основано на предпочтениях или на том, что лучше всего работает в вашей кодовой базе (например, с использованием дополнительной функции implement interface).
В любом случае, будьте уверены, это не так запутанно, как может показаться на первый взгляд — и interface, и type фактически представляют собой два способа сделать одно и то же!
Первоначально опубликовано на https://dev.to 18 сентября 2022 г.