Что делает ключевое слово `is` в TypeScript и как его правильно использовать?
Что такое type guard (защитник типа) и как работает `is`
Ключевое слово is в TypeScript — это часть механизма type guard (защитника типа). Оно создает пользовательскую функцию, которая не просто возвращает true/false, но и сужает тип аргумента для TypeScript внутри условных блоков.
Ваша проблема в примере с boolean именно в этом. Когда вы пишете:
function isString(value: unknown): boolean {
return typeof value === "string";
}
TypeScript видит только: "Функция возвращает boolean". Он не знает, что именно вы проверяли. Для него true — это просто число true, а не "значение теперь точно строка". Поэтому после вызова isString(value) тип value остается unknown.
Как работает `value is string`
Конструкция value is string в возвращаемом типе говорит TypeScript:
- "Если эта функция возвращает
true, то аргументvalueимеет типstring" - "Если возвращает
false— тип не меняется"
Исправленный пример:
function isString(value: unknown): value is string {
return typeof value === "string";
}
function processValue(value: unknown) {
if (isString(value)) {
// Теперь TypeScript знает: value — это string
console.log(value.toUpperCase()); // ✅ Работает!
} else {
// Здесь value все еще unknown
console.log("Not a string");
}
}
Продвинутые сценарии использования
1. Проверка на интерфейсы и сложные типы
Часто используется для проверки, соответствует ли объект определенному интерфейсу:
interface Cat {
meow(): void;
name: string;
}
interface Dog {
bark(): void;
name: string;
}
function isCat(pet: Cat | Dog): pet is Cat {
return (pet as Cat).meow !== undefined;
}
function makeSound(pet: Cat | Dog) {
if (isCat(pet)) {
pet.meow(); // ✅ TypeScript знает: это Cat
} else {
pet.bark(); // ✅ TypeScript знает: это Dog
}
}
2. Работа с discriminated unions (размеченные объединения)
Даже если у вас есть общее поле (например type), is может пригодиться для сложной логики:
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number };
function isCircle(shape: Shape): shape is { kind: "circle"; radius: number } {
return shape.kind === "circle";
}
function getArea(shape: Shape): number {
if (isCircle(shape)) {
return Math.PI * shape.radius ** 2; // ✅ radius доступен
}
return shape.side ** 2; // ✅ side доступен
}
3. Работа с массивами и фильтрацией
is отлично работает с Array.filter():
function isNumber(value: unknown): value is number {
return typeof value === "number";
}
const mixedArray: unknown[] = [1, "hello", 2, "world", 3];
const numbers: number[] = mixedArray.filter(isNumber);
// ✅ TypeScript понимает, что numbers — это number[]
Ограничения
- Вы обязаны написать корректную логику проверки внутри функции. TypeScript не проверяет, правильно ли вы реализовали условие.
- Нельзя использовать
isдля асинхронных функций — type guard должен быть синхронным. - Работает только с одним параметром (первым аргументом функции).
В итоге: is — это мощный инструмент, который помогает TypeScript "понимать" вашу логику и автоматически сужать типы, избавляя вас от лишних приведений типов (as).
Альтернативный подход: встроенные защитники типов
Прежде чем писать собственные функции с is, стоит знать, что TypeScript уже имеет встроенные защитники типов, которые работают "из коробки":
typeof— для примитивов:typeof x === "string"instanceof— для классов:x instanceof Datein— для проверки свойств:"property" in objArray.isArray()— проверка на массив
Пример со встроенным защитником:
function process(value: unknown) {
if (typeof value === "string") {
// ✅ TypeScript автоматически сужает тип до string
console.log(value.toUpperCase());
}
if (value instanceof Date) {
// ✅ TypeScript знает, что это Date
console.log(value.getFullYear());
}
}
Когда использовать собственный is?
Только когда вам нужно объединить несколько проверок в одну функцию или проверить сложную структуру данных (например, интерфейс). Для простых случаев встроенные механизмы TypeScript вполне достаточны и даже предпочтительнее, так как они не требуют написания дополнительного кода и не могут содержать ошибок в логике проверки.
Также помните, что is — это не магия. Если вы напишете:
function isString(val: unknown): val is string {
return true; // ❌ Всегда возвращает true
}
TypeScript поверит вам, и это может привести к ошибкам в рантайме. Всегда проверяйте корректность своей логики.
Ответов пока нет.
Войдите чтобы оставить ответ