ПрограммированиеFrontend разработчик

Опишите механизм наложения типов (Type Guards) в TypeScript и приведите примеры их использования. В чем главное преимущество и какие нюансы стоит учитывать при реализации пользовательских type guard-функций?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

Type Guards — это механизмы, которые позволяют уточнять тип переменной в блоке кода, основываясь на некоторых проверках (например, с помощью typeof, instanceof, либо специальных функций, возвращающих выражения вида param is SomeType).

Главное преимущество — это безопасность и исключение ошибок выполнения за счет проверки типов во время компиляции.

Пример:

interface Fish { swim: () => void } interface Bird { fly: () => void } function isFish(pet: Fish | Bird): pet is Fish { return (pet as Fish).swim !== undefined; } function move(pet: Fish | Bird) { if (isFish(pet)) { pet.swim(); } else { pet.fly(); } }

Здесь функция isFish — это пользовательский type guard.

Нюансы:

  • Любые дополнительные логические проверки должны быть строго связаны с типизацией.
  • Ошибки в type guard-функциях могут привести к неверному определению типов на этапе выполнения.

Вопрос с подвохом.

Вопрос: "Будет ли компилятор TypeScript всегда полагаться только на возвращаемое значение функции guard, или использует еще какой-то анализ внутри функции?"

Ответ: Компилятор TypeScript опирается только на сигнатуру возвращаемого значения param is Type. То, что происходит внутри функции-guard, не анализируется на предмет корректности реализации.

Пример (опасная ошибка!):

function isString(x: any): x is string { return true; } // Компилятор будет считать, что всегда строка, хотя это не так: if (isString(123)) { // тут x типа string, но на самом деле это число }

Примеры реальных ошибок из-за незнания тонкостей темы.


История

На проекте с разделяемыми DTO между фронтом и бэкендом забыли добавить строгую проверку внутри пользовательского type guard. В результате, часть данных ошибочно воспринималась как нужный тип, приводя к сбоям на клиенте при попытке использовать отсутствующее свойство.


История

Разработчик написал type guard, полагаясь на опциональное поле, однако структура данных позволяла вовсе не иметь этого поля. В итоге типовому switch-case не доставало ветви, и компилятор предупреждения не выдавал — в рантайме возникали исключения.


История

В одном из сервисов при переходе на TypeScript полагались только на встроенные type guards (typeof, instanceof). При смене прототипа объектов во время выполнения проверки становились некорректными, что вызвало сложные к отладке баги на проде.