← Назад к вопросам

Во что компилируется type guard в TypeScript

1.0 Junior🔥 31 комментариев
#TypeScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Компиляция Type Guard в TypeScript

Type Guard — это функция, которая проверяет тип значения и помогает TypeScript сузить тип. Вот как они компилируются в JavaScript.

Важное уточнение

Type guard — это исключительно TypeScript конструкция. В JavaScript её вообще нет. Компилятор TypeScript полностью удаляет типы при компиляции.

Пример 1: Простой type guard

TypeScript код

// Функция type guard
function isString(value: unknown): value is string {
  return typeof value === 'string';
}

function processValue(value: unknown) {
  if (isString(value)) {
    // Здесь value имеет тип string
    console.log(value.toUpperCase());
  } else {
    // Здесь value имеет тип unknown
    console.log(value);
  }
}

JavaScript (скомпилированный)

// Компилятор удаляет тип guard синтаксис!
function isString(value) {
  return typeof value === 'string';
}

function processValue(value) {
  if (isString(value)) {
    // Это всё ещё JavaScript
    console.log(value.toUpperCase());
  } else {
    console.log(value);
  }
}

Вывод: Type guard синтаксис value is string полностью удаляется. Остаётся только обычная функция с проверкой типа.

Пример 2: Type guard с объектом

TypeScript

interface User {
  id: number;
  name: string;
  email: string;
}

function isUser(value: unknown): value is User {
  return (
    typeof value === 'object' &&
    value !== null &&
    'id' in value &&
    'name' in value &&
    'email' in value &&
    typeof (value as any).id === 'number' &&
    typeof (value as any).name === 'string' &&
    typeof (value as any).email === 'string'
  );
}

function handleData(data: unknown) {
  if (isUser(data)) {
    // data имеет тип User
    console.log(`User: ${data.name}`);
  } else {
    console.log('Not a user');
  }
}

JavaScript

// Интерфейс удаляется полностью
// Type guard синтаксис удаляется
// Остаётся только логика проверки

function isUser(value) {
  return (
    typeof value === 'object' &&
    value !== null &&
    'id' in value &&
    'name' in value &&
    'email' in value &&
    typeof value.id === 'number' &&
    typeof value.name === 'string' &&
    typeof value.email === 'string'
  );
}

function handleData(data) {
  if (isUser(data)) {
    console.log(`User: ${data.name}`);
  } else {
    console.log('Not a user');
  }
}

Пример 3: instanceof guard

TypeScript

class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

class Dog extends Animal {
  bark() {
    console.log('Woof!');
  }
}

function processAnimal(animal: Animal) {
  if (animal instanceof Dog) {
    // animal имеет тип Dog
    animal.bark();
  }
}

JavaScript

// instanceof — это стандартный JavaScript оператор
// TypeScript типы удаляются

class Animal {
  constructor(name) {
    this.name = name;
  }
}

class Dog extends Animal {
  bark() {
    console.log('Woof!');
  }
}

function processAnimal(animal) {
  if (animal instanceof Dog) {
    animal.bark();
  }
}

Какой синтаксис компилируется, а какой нет

Удаляется (только TypeScript)

// Type guard синтаксис удаляется
function isString(value: unknown): value is string { ... }
//                                  ^^^^^^^^^^^^^^^
//                                  Это удалится

// Типы параметров удаляются
function add(a: number, b: number) { ... }
//           ^^^^^^^^  ^^^^^^^^
//           Удалится

// Типы переменных удаляются
const user: User = { ... };
//          ^^^^^
//          Удалится

// Интерфейсы и type удаляются полностью
interface User { ... }
type Status = 'pending' | 'done';

Остаётся (JavaScript)

// Логика проверки остаётся
if (typeof value === 'string') { ... }
// Это стандартный JavaScript

// instanceof остаётся
if (value instanceof Array) { ... }
// Это стандартный JavaScript

// Условная логика остаётся
if (value !== null && 'name' in value) { ... }
// Это стандартный JavaScript

Эффект type guard на производительность

Нет никакого эффекта

Type guard не добавляет никакого overhead, потому что он удаляется при компиляции:

// TypeScript
function isString(value: unknown): value is string {
  return typeof value === 'string';
}

// JavaScript (идентично)
function isString(value) {
  return typeof value === 'string';
}

// Оба варианта имеют идентичную производительность

Пример 4: Discriminated union type guard

TypeScript

type Result = 
  | { status: 'success'; data: string }
  | { status: 'error'; error: Error };

function isSuccess(
  result: Result
): result is { status: 'success'; data: string } {
  return result.status === 'success';
}

function handleResult(result: Result) {
  if (isSuccess(result)) {
    // result имеет тип { status: 'success'; data: string }
    console.log(result.data);
  } else {
    // result имеет тип { status: 'error'; error: Error }
    console.log(result.error);
  }
}

JavaScript

// Типы удалены, остаётся только логика

function isSuccess(result) {
  return result.status === 'success';
}

function handleResult(result) {
  if (isSuccess(result)) {
    console.log(result.data);
  } else {
    console.log(result.error);
  }
}

Пример 5: Custom type guard

TypeScript

type NonEmptyString = string & { readonly __brand: 'NonEmptyString' };

function isNonEmptyString(value: string): value is NonEmptyString {
  return value.length > 0;
}

function greet(name: NonEmptyString) {
  console.log(`Hello, ${name}`);
}

const userName = 'Alice';
if (isNonEmptyString(userName)) {
  greet(userName);
}

JavaScript

// Brand типы удалены, остаётся логика

function isNonEmptyString(value) {
  return value.length > 0;
}

function greet(name) {
  console.log(`Hello, ${name}`);
}

const userName = 'Alice';
if (isNonEmptyString(userName)) {
  greet(userName);
}

Как TypeScript узнаёт, что это type guard?

TypeScript смотрит на возвращаемый тип функции:

// Обычная функция — возвращает boolean
function isString(value: unknown): boolean {
  return typeof value === 'string';
}

const str: unknown = 'hello';
if (isString(str)) {
  // TypeScript думает, что str всё ещё unknown
  str.toUpperCase(); // ошибка!
}

// Type guard функция — возвращает 'value is Type'
function isStringGuard(value: unknown): value is string {
  return typeof value === 'string';
}

const str: unknown = 'hello';
if (isStringGuard(str)) {
  // TypeScript знает, что str имеет тип string
  str.toUpperCase(); // OK!
}

Когда type guard становится проверкой в runtime

Type guard определяет логику, которая выполняется в runtime:

// TypeScript (compile-time)
function isString(value: unknown): value is string {
  //                              ^^^^^^^^^^^^^^^ - это только для TypeScript
  return typeof value === 'string'; // это выполнится в runtime
}

// Runtime:
// 1. Вызывается функция isString
// 2. Выполняется typeof value === 'string'
// 3. Возвращается boolean
// 4. TypeScript уже скомпилировался, он не участвует

Best Practices

1. Используй type guard вместо множественных проверок

// ПЛОХО: проверка дублируется
if (typeof value === 'string' && value.length > 0) {
  const str = value as string; // нужно приводить тип
  console.log(str.toUpperCase());
}

// ХОРОШО: type guard
function isNonEmptyString(v: unknown): v is string {
  return typeof v === 'string' && v.length > 0;
}

if (isNonEmptyString(value)) {
  console.log(value.toUpperCase()); // TypeScript знает тип
}

2. Типы в type guard должны быть точными

// Правильный синтаксис
function isUser(value: unknown): value is User { ... }

// Неправильный синтаксис
function isUser(value: unknown): value is User | Admin { ... }
// Лучше вернуть union type
function isUserOrAdmin(value: unknown): value is (User | Admin) { ... }

3. Type guard логика должна соответствовать типу

// ХОРОШО: логика соответствует типу
function isUser(obj: unknown): obj is { name: string; email: string } {
  return (
    typeof obj === 'object' &&
    obj !== null &&
    'name' in obj &&
    'email' in obj &&
    typeof obj.name === 'string' &&
    typeof obj.email === 'string'
  );
}

// ПЛОХО: логика не проверяет всё
function isUser(obj: unknown): obj is { name: string; email: string } {
  return typeof obj === 'object'; // слишком слабо!
}

Интересный факт

Type guard — это нулевой стоимости абстракция. То есть:

TypeScript с type guard:  ✓ Type-safe
JavaScript эквивалент:    ✓ Идентичная производительность

Вы платите только за логику проверки типа в runtime,
Без каких-либо额额ных затрат на сам type guard.

Итог

Type guard компилируется в:

  1. Удаление синтаксиса value is Type — это TypeScript only
  2. Сохранение логики проверки — это остаётся в JavaScript
  3. Обычная функция — которая возвращает boolean

Type guard — это инструмент TypeScript для сужения типов. В runtime это просто функция, которая проверяет условие. Никакого магии или overhead.

Во что компилируется type guard в TypeScript | PrepBro