Можно ли создать второй интерфейс на основе первого, включающий все его поля, и как это сделать в TypeScript?
Что проверяют
Знаете ли вы extends у интерфейсов и понимаете ли, чем он отличается от пересечения типов. Попутно смотрят, умеете ли вы собирать производные типы из существующих, а не копировать поля руками.
Как отвечать
Да, для этого есть extends, причём наследовать можно сразу от нескольких интерфейсов:
interface User { id: number; name: string }
interface Admin extends User { scopes: string[] }
type Draft = Omit<User, "id">;
type WithMeta = User & { updatedAt: string };Что стоит добавить:
extendsпроверяет совместимость в момент объявления и даёт понятную ошибку, а пересечение через&складывает типы молча, и при конфликте поле получает типnever;- псевдоним типа умеет то, чего не умеет интерфейс: объединения, кортежи, условные и отображаемые типы;
- когда нужны не все поля, берут
Pick,Omit,Partial,Required,Readonly, а не пишут новый интерфейс; - интерфейс может расширять и псевдоним типа, если тот описывает объект.
Где спотыкаются
Пробуют переопределить унаследованное поле несовместимым типом. Сузить разрешено: литеральный тип поверх number пройдёт. Заменить number на string нельзя, компилятор скажет, что типы несовместимы.
Путают наследование интерфейсов с наследованием классов. Интерфейс не несёт реализации и целиком стирается при компиляции, поэтому проверить его через instanceof во время выполнения не выйдет, нужен свой предикат типа.
Наследуют всё подряд там, где просится Omit. Тип формы создания получает id и дату создания, которых у него быть не должно, а проверка лишних свойств срабатывает только на объектных литералах и такое значение спокойно пропускает.