> Как работают 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:
-
Встроенные операторы:
typeofдля примитивов (string,number,boolean,symbol,bigint,undefined,function),instanceofдля классов, проверкаinдля свойств объектов. -
Пользовательские type guards: функции, возвращающие
x is Type. Это даёт гибкость для сложных проверок, например, проверка структуры объекта или наличия определённых полей. -
Discriminated unions: объекты с общим литеральным полем (discriminant), по которому TypeScript может точно определить тип. Это наиболее надёжный и производительный способ.
-
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 uniontype 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 сужен до circlecase 'square':return shape.side ** 2; // shape сужен до squarecase 'triangle':return (shape.base * shape.height) / 2;}}// Пользовательский type guardinterface 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-типа
> Похожие задачи по frontend
Что такое generics в TypeScript и как они помогают создавать переиспользуемые компоненты?
Что такое операторы Pick, Partial, Omit, Required, NonNullable и Exclude в TypeScript
Как типизировать объект с разными ключами и значениями в TypeScript?
Можно ли объединить несколько типов в один тип в TypeScript и как это сделать?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью