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 objectsinstanceof не работает с объектными литералами; используйте in или пользовательские type guards.
  • Полагаться на typeof для массивовtypeof === "object"; для проверки массива используйте Array.isArray(x).
  • Не проверять тип перед использованием unknown — переменная типа unknown требует narrowing перед любым обращением к свойствам.

Связанные темы

Ресурсы