Типизация callback-функций

Библиотека Web Vitals предоставляет набор инструментов для измерения ключевых метрик производительности веб-страниц, таких как Largest Contentful Paint (LCP), First Input Delay (FID), Cumulative Layout Shift (CLS) и другие. Каждая метрика отслеживается через callback-функции, передаваемые в API библиотеки. Правильная типизация этих функций является критически важной для стабильной интеграции в проекты на TypeScript и для предотвращения ошибок при обработке данных метрик.

Основные принципы callback-функций

Callback-функции в Web Vitals принимают один объект, содержащий информацию о метрике. Структура этого объекта определяется интерфейсами TypeScript, предоставляемыми библиотекой. Все метрики имеют общие поля:

  • name — название метрики ('LCP' | 'FID' | 'CLS' | ...).
  • value — числовое значение метрики.
  • delta — изменение значения метрики с предыдущего измерения.
  • id — уникальный идентификатор измерения.
  • entries — массив объектов PerformanceEntry, относящихся к данной метрике (не всегда присутствует).
import { Metric } from 'web-vitals';

function handleMetric(metric: Metric) {
  console.log(metric.name, metric.value, metric.delta);
}

В TypeScript интерфейс Metric выглядит следующим образом:

export interface Metric {
  name: string;
  value: number;
  delta: number;
  id: string;
  entries?: PerformanceEntry[];
}

Использование строгой типизации позволяет IDE подсказывать свойства метрики, предотвращает опечатки и делает код самодокументированным.

Специфические callback-функции для каждой метрики

Каждая метрика имеет свои нюансы в типизации и поведении callback-функции.

Largest Contentful Paint (LCP)

  • Тип callback: (metric: Metric) => void
  • Поле entries содержит массив объектов LargestContentfulPaintEntry.
  • Пример использования:
import { getLCP, LCPMetric } from 'web-vitals';

function handleLCP(metric: LCPMetric) {
  console.log(`LCP: ${metric.value}ms`);
  console.log(`Элемент:`, metric.entries?.[0]?.element);
}

getLCP(handleLCP);

Интерфейс LCPMetric расширяет Metric и уточняет тип entries:

export interface LCPMetric extends Metric {
  entries?: Array<LargestContentfulPaintEntry>;
}

First Input Delay (FID)

  • Тип callback: (metric: Metric) => void
  • Поле entries содержит EventTiming объекты, связанные с первым пользовательским взаимодействием.
import { getFID, FIDMetric } from 'web-vitals';

function handleFID(metric: FIDMetric) {
  console.log(`FID: ${metric.value}ms`);
  console.log(`Событие:`, metric.entries?.[0]?.name);
}

getFID(handleFID);

Cumulative Layout Shift (CLS)

  • Тип callback: (metric: Metric) => void
  • Метрика CLS имеет массив entries с LayoutShift событиями.
  • Пример:
import { getCLS, CLSMetric } from 'web-vitals';

function handleCLS(metric: CLSMetric) {
  console.log(`CLS: ${metric.value}`);
  if (metric.entries) {
    metric.entries.forEach(entry => {
      console.log(`Смещение: ${entry.value}, источник:`, entry.sources);
    });
  }
}

getCLS(handleCLS);

Обобщение callback-функций

Для удобства и переиспользования можно определить универсальный тип callback:

type WebVitalsCallback<T extends Metric = Metric> = (metric: T) => void;

Это позволяет строго типизировать функцию под конкретную метрику:

const logLCP: WebVitalsCallback<LCPMetric> = metric => {
  console.log(metric.value);
};

Типизация для расширенного использования

  • Фильтрация метрик: Можно создавать обобщённые функции, которые принимают только определённые метрики, используя условные типы TypeScript:
type CoreMetric = LCPMetric | FIDMetric | CLSMetric;

function handleCoreMetric(metric: CoreMetric) {
  switch (metric.name) {
    case 'LCP':
      console.log('LCP value:', metric.value);
      break;
    case 'FID':
      console.log('FID value:', metric.value);
      break;
    case 'CLS':
      console.log('CLS value:', metric.value);
      break;
  }
}
  • Интеграция с аналитикой: Типизация callback позволяет передавать метрики в сторонние системы аналитики без потери информации о структуре объекта:
function sendToAnalytics<T extends Metric>(metric: T) {
  fetch('/analytics', {
    method: 'POST',
    body: JSON.stringify({
      metricName: metric.name,
      metricValue: metric.value,
      metricDelta: metric.delta
    })
  });
}

Рекомендации по типизации

  1. Использовать предоставленные библиотекой интерфейсы (Metric, LCPMetric, FIDMetric, CLSMetric) для строгой типизации.
  2. Определять универсальные типы callback через обобщённые параметры TypeScript.
  3. Проверять наличие массива entries перед обращением к его элементам.
  4. Для крупных проектов создавать вспомогательные функции-обёртки для стандартных обработчиков метрик.

Типизация callback-функций Web Vitals повышает безопасность кода, улучшает автодополнение в IDE и облегчает интеграцию метрик в аналитические системы, предотвращая ошибки на этапе компиляции.