TYPESCRIPT
#typescript#events#dom#handlers#typing

TypeScript: типизация событий и обработчиков

Правильная типизация обработчиков событий DOM и кастомных событий. Работа с MouseEvent, KeyboardEvent и создание типобезопасных компонентов.

Типизация событий и обработчиков помогает избежать ошибок при работе с DOM и создании компонентов.

Типизация обработчика клика

// Типизация обработчика события
type ButtonClickHandler = (event: MouseEvent) => void;

// Компонент с типизированным обработчиком
interface ButtonProps {
  label: string;
  onClick: ButtonClickHandler;
  disabled?: boolean;
}

function Button({ label, onClick, disabled = false }: ButtonProps) {
  return (
    <button onClick={onClick} disabled={disabled}>
      {label}
    </button>
  );
}

// Использование
const handleClick = (event: MouseEvent) => {
  console.log("Clicked!", event.target);
};

<Button 
  label="Submit" 
  onClick={handleClick}
  disabled={false}
/>

Типизация клавиатурных событий

type KeyboardHandler = (event: KeyboardEvent) => void;

interface InputProps {
  value: string;
  onChange: (value: string) => void;
  onKeyDown?: KeyboardHandler;
  placeholder?: string;
}

function Input({ value, onChange, onKeyDown, placeholder }: InputProps) {
  const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
    if (onKeyDown) {
      onKeyDown(event);
    }
    
    // Проверка конкретных клавиш
    if (event.key === 'Enter') {
      // Обработка Enter
    }
  };

  return (
    <input
      value={value}
      onChange={(e) => onChange(e.target.value)}
      onKeyDown={handleKeyDown}
      placeholder={placeholder}
    />
  );
}

Типизация кастомных событий

// Определяем тип кастомного события
interface CustomEvent<T = any> {
  type: string;
  detail: T;
  timestamp: number;
}

// Тип обработчика кастомного события
type CustomEventHandler<T> = (event: CustomEvent<T>) => void;

// Пример использования
interface UserCreatedEvent {
  userId: number;
  userName: string;
}

const handleUserCreated: CustomEventHandler<UserCreatedEvent> = (event) => {
  console.log(`User ${event.detail.userName} created at ${event.timestamp}`);
};

Типизация событий формы

type FormSubmitHandler = (event: FormEvent<HTMLFormElement>) => void;
type InputChangeHandler = (event: ChangeEvent<HTMLInputElement>) => void;

interface FormProps {
  onSubmit: FormSubmitHandler;
  children: React.ReactNode;
}

function Form({ onSubmit, children }: FormProps) {
  const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    onSubmit(event);
  };

  return <form onSubmit={handleSubmit}>{children}</form>;
}

Типизация событий с данными

interface EventWithData<T> {
  originalEvent: Event;
  data: T;
}

type DataEventHandler<T> = (event: EventWithData<T>) => void;

// Использование
interface ProductData {
  id: number;
  name: string;
}

const handleProductSelect: DataEventHandler<ProductData> = (event) => {
  console.log('Selected product:', event.data.name);
  // event.originalEvent содержит оригинальное событие
};

Типизация обработчиков с опциональными параметрами

interface ComponentProps {
  onClick?: (event: MouseEvent) => void;
  onHover?: (event: MouseEvent) => void;
  onFocus?: (event: FocusEvent) => void;
}

function Component({ onClick, onHover, onFocus }: ComponentProps) {
  return (
    <div
      onClick={onClick}
      onMouseEnter={onHover}
      onFocus={onFocus}
    >
      Content
    </div>
  );
}

Usage:

Всегда типизируй обработчики событий. Это даёт автодополнение, проверку типов и предотвращает ошибки в рантайме.

Notes:

⚠️ Используй конкретные типы событий (MouseEvent, KeyboardEvent) вместо общего Event. TypeScript предоставляет типы для всех стандартных DOM-событий. Для React используй типы из @types/react.