TypeScript в React
Как Type Guard сужает union-тип?
Type guard выполняет runtime-проверку, после которой TypeScript сужает union в соответствующей ветке. Встроенные варианты: typeof для примитивов, instanceof для экземпляров, оператор in для свойства. Для собственных данных пишут функцию-предикат value is Type, но компилятор доверяет её реализации, поэтому ошибочный предикат создаёт ложную безопасность. Для доменных union удобнее discriminator, например поле kind, и исчерпывающий switch. Guard проверяет только то, что написано; наличие одного поля не валидирует весь внешний JSON. На границе API нужна полная схема или последовательная проверка структуры.
Ссылки для изучения
Почему unknown безопаснее any для внешних данных?
any отключает проверку: у значения можно читать любое поле, вызывать его и присваивать несовместимому типу. unknown заставляет сначала доказать форму через typeof, guard или schema validator. Поэтому ответ внешнего API разбирают как unknown, валидируют обязательные поля и только затем передают в доменный код. Type assertion as User ничего не проверяет во время выполнения и уместен лишь там, где инвариант уже обеспечен другим способом. unknown не делает данные корректными сам по себе, но не позволяет случайно использовать их до проверки.
Ссылки для изучения
Когда выбрать type, а когда interface?
interface удобно описывает форму объекта и публичные расширяемые контракты: его можно extends, а декларации с одним именем сливаются. type умеет alias для union, tuple, primitive, conditional и mapped type, а объекты комбинирует через intersection. Для обычной закрытой формы объекта оба варианта часто равнозначны. Выбор делают по намерению: declaration merging полезен для расширяемого API, но опасен для внутренней модели, где случайное дополнение имени нежелательно. Не стоит формулировать правило «interface всегда для объектов»: важнее единообразие проекта и нужные возможности типа.
Ссылки для изучения
Примеры хороших ответов из реальных собеседований
- #14 Собеседование Senior Frontend разработчика из FAANG · 1:13:40–1:14:38Мок-собеседование · Ответ кандидата
Кандидат предлагает interface для описания объектов, а type — для union и вычисляемых типов. Это его рабочее соглашение, а не обязательное правило TypeScript.
Как работает слияние деклараций interface?
Две декларации interface с одним именем в одной области объединяют члены. Свойства с разными именами складываются; повторное non-function свойство должно иметь совместимый одинаковый тип, иначе компилятор выдаст ошибку. Перегрузки методов также объединяются по правилам TypeScript. Это позволяет расширять типы библиотек через module augmentation, но случайное повторение имени может незаметно расширить публичный контракт. type alias не сливается и при повторной декларации ошибочен. Для закрытой доменной модели отсутствие merging часто является более безопасным намерением.
Ссылки для изучения
Как keyof связывает ключ объекта с типом параметра?
keyof T создаёт union известных ключей типа T. Если функция принимает K extends keyof T, параметр ключа нельзя передать произвольной строкой, а возвращаемый тип T[K] зависит от выбранного свойства. Например, get(user, "age") получает тип поля age, а опечатка отклоняется компилятором. Для index signature результат keyof может включать string или number, поэтому точность зависит от исходного типа. Этот механизм существует только при компиляции и не проверяет, какие ключи пришли во внешнем JSON во время выполнения.
Ссылки для изучения
Что такое mapped type в TypeScript?
Mapped type строит новый object type, перебирая union ключей, обычно keyof T: [K in keyof T]. Для каждого ключа можно выбрать новый тип через T[K], добавить или снять модификаторы readonly и ?, а также переименовать ключ через as. Так устроены идеи Partial, Required, Readonly и Pick. Mapped type вычисляется компилятором и не копирует объект в runtime. Сложные условные преобразования стоит именовать по смыслу, иначе короткая запись становится труднее обычного явного интерфейса.
Ссылки для изучения
Как ограничить generic в TypeScript?
Ограничение пишут через extends, чтобы generic мог использовать только гарантированные свойства. Например, K extends keyof T связывает ключ с объектом, а возвращаемый тип T[K] сохраняет тип конкретного поля. Для функции, которой нужна длина, подойдёт T extends { length: number }; передать число уже нельзя. Constraint не фиксирует один конкретный тип, а задаёт минимальный контракт. Не следует заменять его assertion внутри функции: тогда ошибка перемещается из места вызова в runtime. Слишком широкий constraint вроде object почти не даёт полезных операций.
Ссылки для изучения







