---
title: TypeScript в React
questionDates:
  q-transfer-0437: '2026-10-01'
  q-transfer-0438: '2026-10-01'
  q-transfer-0439: '2026-10-01'
  q-transfer-0457: '2026-10-01'
  q-transfer-0458: '2026-10-01'
  q-transfer-0459: '2026-10-01'
  q-transfer-0460: '2026-10-01'
seo:
  description: >-
    Тема «TypeScript в React» для собеседования React Developer. Как Type Guard
    сужает union-тип? Почему unknown безопаснее any для внешних данных?
  title: TypeScript в React — React Developer
---

[Все темы React Developer](/prep/react-developer)

## Как Type Guard сужает union-тип? [#q-transfer-0437]

Type guard выполняет runtime-проверку, после которой TypeScript сужает union в соответствующей ветке. Встроенные варианты: `typeof` для примитивов, `instanceof` для экземпляров, оператор `in` для свойства. Для собственных данных пишут функцию-предикат `value is Type`, но компилятор доверяет её реализации, поэтому ошибочный предикат создаёт ложную безопасность. Для доменных union удобнее discriminator, например поле `kind`, и исчерпывающий `switch`. Guard проверяет только то, что написано; наличие одного поля не валидирует весь внешний JSON. На границе API нужна полная схема или последовательная проверка структуры.

:::note[Ссылки для изучения]

1. [Защитники типа: runtime-условие и сужение union](https://scriptdev.ru/guide/036/)
2. [Пользовательский Type Guard. Ulbi TV, с 1:08:34](https://www.youtube.com/watch?v=LWtHl__oEWc&t=4114s)

:::

---

## Почему unknown безопаснее any для внешних данных? [#q-transfer-0438]

`any` отключает проверку: у значения можно читать любое поле, вызывать его и присваивать несовместимому типу. `unknown` заставляет сначала доказать форму через `typeof`, guard или schema validator. Поэтому ответ внешнего API разбирают как `unknown`, валидируют обязательные поля и только затем передают в доменный код. Type assertion `as User` ничего не проверяет во время выполнения и уместен лишь там, где инвариант уже обеспечен другим способом. `unknown` не делает данные корректными сам по себе, но не позволяет случайно использовать их до проверки.

:::note[Ссылки для изучения]

1. [unknown и any: проверка доступа к свойствам и вызова](https://scriptdev.ru/guide/014/)
2. [Безопасная обработка unknown вместо any. Ulbi TV, с 23:30](https://www.youtube.com/watch?v=LWtHl__oEWc&t=1410s)

:::

---

## Когда выбрать type, а когда interface? [#q-transfer-0439]

`interface` удобно описывает форму объекта и публичные расширяемые контракты: его можно `extends`, а декларации с одним именем сливаются. `type` умеет alias для union, tuple, primitive, conditional и mapped type, а объекты комбинирует через intersection. Для обычной закрытой формы объекта оба варианта часто равнозначны. Выбор делают по намерению: declaration merging полезен для расширяемого API, но опасен для внутренней модели, где случайное дополнение имени нежелательно. Не стоит формулировать правило «interface всегда для объектов»: важнее единообразие проекта и нужные возможности типа.

:::note[Ссылки для изучения]

1. [Псевдонимы type: union, intersection и объектные типы](https://scriptdev.ru/guide/017/)
1. [Интерфейсы и слияние деклараций](https://scriptdev.ru/guide/021/)
1. [Выбор между type и interface. Ulbi TV, с 1:51:30](https://www.youtube.com/watch?v=LWtHl__oEWc&t=6690s)

:::

---

## Как работает слияние деклараций interface? [#q-transfer-0457]

Две декларации `interface` с одним именем в одной области объединяют члены. Свойства с разными именами складываются; повторное non-function свойство должно иметь совместимый одинаковый тип, иначе компилятор выдаст ошибку. Перегрузки методов также объединяются по правилам TypeScript. Это позволяет расширять типы библиотек через module augmentation, но случайное повторение имени может незаметно расширить публичный контракт. `type` alias не сливается и при повторной декларации ошибочен. Для закрытой доменной модели отсутствие merging часто является более безопасным намерением.

:::note[Ссылки для изучения]

1. [Слияние интерфейсов: свойства, совместимость и перегрузки](https://scriptdev.ru/guide/021/)
2. [Слияние деклараций interface. Ulbi TV, с 1:53:04](https://www.youtube.com/watch?v=LWtHl__oEWc&t=6784s)

:::

---

## Как keyof связывает ключ объекта с типом параметра? [#q-transfer-0458]

`keyof T` создаёт union известных ключей типа `T`. Если функция принимает `K extends keyof T`, параметр ключа нельзя передать произвольной строкой, а возвращаемый тип `T[K]` зависит от выбранного свойства. Например, `get(user, "age")` получает тип поля `age`, а опечатка отклоняется компилятором. Для index signature результат `keyof` может включать `string` или `number`, поэтому точность зависит от исходного типа. Этот механизм существует только при компиляции и не проверяет, какие ключи пришли во внешнем JSON во время выполнения.

:::note[Ссылки для изучения]

1. [keyof и mapped types: ключи, типы полей и преобразование свойств](https://habr.com/ru/companies/timeweb/articles/682748/)
2. [keyof и типизированное чтение свойства. Ulbi TV, с 1:31:50](https://www.youtube.com/watch?v=LWtHl__oEWc&t=5510s)

:::

---

## Что такое mapped type в TypeScript? [#q-transfer-0459]

Mapped type строит новый object type, перебирая union ключей, обычно `keyof T`: `[K in keyof T]`. Для каждого ключа можно выбрать новый тип через `T[K]`, добавить или снять модификаторы `readonly` и `?`, а также переименовать ключ через `as`. Так устроены идеи `Partial`, `Required`, `Readonly` и `Pick`. Mapped type вычисляется компилятором и не копирует объект в runtime. Сложные условные преобразования стоит именовать по смыслу, иначе короткая запись становится труднее обычного явного интерфейса.

:::note[Ссылки для изучения]

1. [keyof и mapped types: ключи, типы полей и преобразование свойств](https://habr.com/ru/companies/timeweb/articles/682748/)
2. [Mapped types на основе keyof. Ulbi TV, с 1:58:00](https://www.youtube.com/watch?v=LWtHl__oEWc&t=7080s)

:::

---

## Как ограничить generic в TypeScript? [#q-transfer-0460]

Ограничение пишут через `extends`, чтобы generic мог использовать только гарантированные свойства. Например, `K extends keyof T` связывает ключ с объектом, а возвращаемый тип `T[K]` сохраняет тип конкретного поля. Для функции, которой нужна длина, подойдёт `T extends { length: number }`; передать число уже нельзя. Constraint не фиксирует один конкретный тип, а задаёт минимальный контракт. Не следует заменять его assertion внутри функции: тогда ошибка перемещается из места вызова в runtime. Слишком широкий constraint вроде `object` почти не даёт полезных операций.

:::note[Ссылки для изучения]

1. [Ограничения generic через extends и минимальный контракт](https://metanit.com/web/typescript/3.5.php)
2. [Ограничения generic через extends. Ulbi TV, с 50:45](https://www.youtube.com/watch?v=LWtHl__oEWc&t=3045s)

:::
