ПрограммированиеFullstack-разработчик

Каким образом работает расширение типов (extends), какие есть нюансы в использовании с типами и интерфейсами, и как это влияет на структуру вашего проекта?

Проходите собеседования с ИИ помощником Hintsage

Ответ

В TypeScript расширять (наследовать) типы можно как с помощью interface extends, так и с помощью type & type (intersection types). Также интерфейсы могут расширять типы, и наоборот.

Интерфейсы используют ключевое слово extends для наследования свойств:

interface Animal { name: string; } interface Bird extends Animal { wings: number; }

Типы могут быть объединены через &:

type Animal = { name: string }; type Bird = Animal & { wings: number };

Также интерфейс может расширять другой тип:

type Base = { id: number }; interface Derived extends Base { description: string; }

Особенности:

  • Интерфейсы поддерживают декларативное слияние (declaration merging), типы — нет.
  • Интерфейсы рекомендуются, если ожидается расширение других сущностей (например, для библиотек).
  • Вложенные extends могут стать причиной сложной иерархии, усложнить поддержку и создавать конфликт имен.

Вопрос с подвохом

Можно ли тип (type) расширить через интерфейс или наоборот? Какую ошибку совершает большинство?

Многие считают, что расширять можно только интерфейсы через интерфейсы, но на самом деле интерфейс может расширять тип:

type Basic = { flag: boolean }; interface Extra extends Basic { name: string; }

А вот тип через extends другие типы расширять не может — только через пересечение типов (&).

Примеры реальных ошибок из-за незнания тонкостей темы


История

В одном крупном проекте объединяли интерфейсы через extends, забывая, что одноимённые свойства должны совпадать по типу. Когда кто-то изменил тип свойства в родительском интерфейсе, в дочерних возникли silent-конфликты, база перестала соответствовать API.

История

В библиотеке написали type-алиасы с перекрытием свойств через & (пересечения), но некоторые свойства сделали несовместимыми по типу. TypeScript пропустил это на этапе компиляции, но реально в рантайме системы появились неопределённые поля.

История

Команда считала, что interface нельзя расширять типом, и для расширения общего функционала переписывали все структуры с type на interface, тратя много времени и усилий — хотя можно было просто расширять существующие типы нестандартным образом.