Type Guards: typeof и instanceof
Type Guards (сужение типов) — конструкции в TypeScript, которые в ветке
if/switchсужают тип переменной до более конкретного:typeofработает с примитивами,instanceof— с объектами и классами.
Зачем нужно
При работе с union-типами (string | number, User | null) нужно знать конкретный тип перед использованием методов. TypeScript автоматически сужает тип внутри условных блоков после проверок typeof/instanceof, устраняя необходимость в кастах.
Где используется
- Обработка
string | number | booleanв общих функциях - Проверка
nullиundefined - Различение классов в union:
Cat | Dog - Обработка ошибок:
Error | string - Валидация данных из
unknown
Основной контент
typeof guard
Работает для примитивных типов: string, number, boolean, bigint, symbol, function, undefined.
function formatValue(value: string | number | boolean): string {
if (typeof value === "string") {
// value: string здесь
return value.toUpperCase();
}
if (typeof value === "number") {
// value: number здесь
return value.toFixed(2);
}
// value: boolean здесь
return value ? "Yes" : "No";
}
typeof для null/undefined
function greet(name: string | undefined): string {
if (typeof name === "undefined") {
return "Hello, Guest!";
}
return `Hello, ${name}!`; // name: string
}
// Более идиоматичный вариант:
function greet2(name?: string): string {
if (name === undefined) {
return "Hello, Guest!";
}
return `Hello, ${name}!`;
}
instanceof guard
Работает с классами и конструкторами.
class Cat {
meow: void { console.log("Meow"); }
}
class Dog {
bark: void { console.log("Woof"); }
}
function makeSound(animal: Cat | Dog): void {
if (animal instanceof Cat) {
animal.meow; // animal: Cat
} else {
animal.bark; // animal: Dog
}
}
// Обработка ошибок
function handleError(error: unknown): string {
if (error instanceof Error) {
return error.message; // error: Error
}
if (typeof error === "string") {
return error; // error: string
}
return "Unknown error";
}
in operator как type guard
interface Admin { role: "admin"; permissions: string }
interface User { role: "user"; name: string }
function getAccess(account: Admin | User): string {
if ("permissions" in account) {
// account: Admin
return account.permissions.join(", ");
}
// account: User
return account.name;
}
Сужение в switch
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number };
function area(shape: Shape): number {
switch (shape.kind) {
case "circle": return Math.PI * shape.radius ** 2;
case "square": return shape.side ** 2;
}
}
Truthiness narrowing
function processName(name: string | null | undefined): string {
if (name) {
// name: string (null и undefined — falsy)
return name.trim();
}
return "anonymous";
}
Частые ошибки
typeof null === "object"— классическая ловушка JavaScript; всегда проверяйтеvalue !== nullвместе сtypeof value === "object".instanceofс plain objects —instanceofне работает с объектными литералами; используйтеinили пользовательские type guards.- Полагаться на
typeofдля массивов —typeof === "object"; для проверки массива используйтеArray.isArray(x). - Не проверять тип перед использованием
unknown— переменная типаunknownтребует narrowing перед любым обращением к свойствам.
Связанные темы
- Пользовательские Type Guards
- Assertion Functions
- Discriminated Unions
- in оператор для сужения
- any, unknown -- различия
- _MOC TypeScript