> Как работают type guards в TypeScript (TypeScript)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Точка, Арго

Стек: TypeScript

> Пример ответа

Короткий ответ

Type guards - это механизм сужения типа (type narrowing) в TypeScript, который позволяет компилятору определить более конкретный тип переменной внутри условного блока. Реализуются через пользовательские функции с возвращаемым типом x is Type, встроенные операторы typeof, instanceof, проверку на null/undefined, а также через discriminated unions. Type guards работают на этапе компиляции и не влияют на runtime, если не используются пользовательские проверки.

Подробное объяснение

TypeScript - статически типизированный язык, но в runtime JavaScript не имеет типов. Type guards решают проблему, когда переменная может иметь union-тип, и нужно безопасно работать с конкретным вариантом. Компилятор анализирует поток управления (control flow analysis) и сужает тип на основе условий.

Основные виды type guards:

  1. Встроенные операторы: typeof для примитивов (string, number, boolean, symbol, bigint, undefined, function), instanceof для классов, проверка in для свойств объектов.

  2. Пользовательские type guards: функции, возвращающие x is Type. Это даёт гибкость для сложных проверок, например, проверка структуры объекта или наличия определённых полей.

  3. Discriminated unions: объекты с общим литеральным полем (discriminant), по которому TypeScript может точно определить тип. Это наиболее надёжный и производительный способ.

  4. Assertion functions: функции с возвращаемым типом asserts x is Type, которые выбрасывают ошибку при несоответствии.

Type guards работают на уровне типов - они не изменяют runtime-поведение, но позволяют компилятору корректно вывести тип. Для пользовательских type guards важно, чтобы функция действительно проверяла тип в runtime, иначе возможны ошибки.

На практике

В реальных проектах type guards используются для:

  • Обработки ответов API с неизвестной структурой
  • Работы с discriminated unions в редюсерах (Redux, Zustand)
  • Валидации данных форм
  • Type-safe работы с DOM-элементами
  • Фильтрации массивов с union-типами

Для сложных структур предпочтительнее discriminated unions - они дают лучшую производительность и читаемость. Пользовательские type guards стоит использовать, когда нужна кастомная логика проверки, например, проверка наличия всех обязательных полей.

Пример кода

TYPESCRIPT
// Discriminated union
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'square'; side: number }
| { kind: 'triangle'; base: number; height: number };
function getArea(shape: Shape): number {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius ** 2; // shape сужен до circle
case 'square':
return shape.side ** 2; // shape сужен до square
case 'triangle':
return (shape.base * shape.height) / 2;
}
}
// Пользовательский type guard
interface User { name: string; email: string; }
interface Admin extends User { role: 'admin'; permissions: string[]; }
function isAdmin(user: User): user is Admin {
return 'role' in user && user.role === 'admin';
}
function processUser(user: User) {
if (isAdmin(user)) {
console.log(user.permissions); // TypeScript знает, что это Admin
}
}
// Type guard для фильтрации массива
const items: (string | number)[] = ['a', 1, 'b', 2];
const strings = items.filter((item): item is string => typeof item === 'string');
// strings: string[]

Как отвечать на собеседовании

Начни с определения: type guards - это механизм сужения типа на основе runtime-проверок. Перечисли основные виды: typeof, instanceof, discriminated unions, пользовательские функции. Объясни, что это compile-time фича, которая не влияет на runtime, но требует корректной реализации проверок.

Подчеркни практическую пользу: type guards делают код безопаснее, уменьшают количество as и any, улучшают читаемость. Упомяни, что discriminated unions - предпочтительный подход для сложных структур из-за производительности и надёжности.

Если спросят про отличия от type assertions (as), объясни: type guard сужает тип на основе проверки, а assertion - принудительное указание типа без проверки.

Что проверяет интервьюер

  • Понимание разницы между runtime и compile-time в TypeScript
  • Умение выбирать подходящий type guard под задачу
  • Знание discriminated unions как идиоматического подхода
  • Понимание, что пользовательские type guards должны быть корректными - иначе возможны баги
  • Способность объяснить, как работает control flow analysis

Типичные ошибки

  • Использование typeof для объектов или массивов - typeof [] вернёт 'object'
  • Создание type guard, который не проверяет тип в runtime (например, всегда возвращает true)
  • Путаница между type guard и type assertion - guard сужает, assertion утверждает
  • Игнорирование discriminated unions в пользу сложных пользовательских guards
  • Неправильная обработка null и undefined - они могут быть частью union-типа

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью