TypeScript и типизация

Haunted — это библиотека для создания веб-компонентов на основе функциональных подходов, вдохновлённых React Hooks. Использование TypeScript в Haunted позволяет обеспечить строгую типизацию компонентов, их свойств и состояний, что повышает безопасность кода и удобство работы с ним в больших проектах.


Типизация компонентов

В Haunted компоненты создаются как функции, возвращающие шаблон html. Для TypeScript можно задать типы параметров функции, описывающих свойства компонента. Например:

import { html, component } from 'haunted';

interface MyComponentProps {
  name: string;
  age?: number;
}

function MyComponent({ name, age }: MyComponentProps) {
  return html`<p>${name} ${age ?? 'Возраст не указан'}</p>`;
}

customElements.define('my-component', component(MyComponent));

Здесь MyComponentProps определяет интерфейс свойств: name обязательное, age — необязательное. TypeScript гарантирует, что при использовании компонента в коде будут соблюдены эти правила.


Хуки и их типизация

Haunted предоставляет встроенные хуки, такие как useState, useEffect, useRef. Для TypeScript важно правильно типизировать состояния и возвращаемые значения хуков.

useState

import { useState } from 'haunted';

function Counter() {
  const [count, setCount] = useState<number>(0);

  return html`
    <button @click=${() => setCount(count + 1)}>Нажато ${count} раз</button>
  `;
}

В этом примере <number> указывает TypeScript, что count всегда будет числом. Попытка присвоить строку вызовет ошибку компиляции.

useRef

import { useRef } from 'haunted';

function InputFocus() {
  const inputRef = useRef<HTMLInputElement>();

  return html`
    <input type="text" ref=${inputRef} />
    <button @click=${() => inputRef.current?.focus()}>Фокус</button>
  `;
}

useRef типизирован с помощью дженерика, что позволяет безопасно обращаться к DOM-элементу внутри компонента.


Типизация пользовательских событий

Haunted поддерживает стандартные DOM-события, но TypeScript позволяет типизировать их для более строгого контроля:

function ClickLogger() {
  const handleClick = (event: MouseEvent) => {
    console.log('Координаты клика:', event.clientX, event.clientY);
  };

  return html`<button @click=${handleClick}>Кликни меня</button>`;
}

Тип MouseEvent обеспечивает автодополнение и проверку свойств события, таких как clientX и clientY.


Интерфейсы для пропсов с дефолтными значениями

Можно комбинировать интерфейсы и дефолтные значения, чтобы свойства были опциональными, но при этом типизированными:

interface ButtonProps {
  label?: string;
  disabled?: boolean;
}

function Button({ label = 'Кнопка', disabled = false }: ButtonProps) {
  return html`<button ?disabled=${disabled}>${label}</button>`;
}

TypeScript гарантирует, что свойства имеют ожидаемые типы, даже если они не переданы при вызове компонента.


Типизация слотов и контента

Haunted позволяет использовать слоты для передачи содержимого в компонент. Типизация контента может быть обеспечена через интерфейсы для children:

interface CardProps {
  title: string;
  children?: HTMLElement[];
}

function Card({ title, children }: CardProps) {
  return html`
    <div class="card">
      <h2>${title}</h2>
      <div class="content">${children}</div>
    </div>
  `;
}

Хотя HTML слоты динамические, TypeScript помогает явно указать ожидаемый тип вложенного контента.


Типизация кастомных хуков

Создание собственных хуков в Haunted также требует типизации, особенно если они возвращают состояние или функции:

function useCounter(initial: number = 0): [number, () => void] {
  const [count, setCount] = useState<number>(initial);
  const increment = () => setCount(count + 1);
  return [count, increment];
}

function Counter() {
  const [count, increment] = useCounter();
  return html`<button @click=${increment}>${count}</button>`;
}

Тип [number, () => void] гарантирует корректность использования возвращаемого массива.


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

  • Всегда создавать интерфейсы для пропсов компонентов.
  • Типизировать состояния useState, ссылки useRef и события.
  • Использовать дефолтные значения с типами для опциональных пропсов.
  • При создании кастомных хуков явно указывать возвращаемый тип.
  • Для сложных компонентов с вложенными элементами использовать массивы HTMLElement или типы JSX-совместимых шаблонов.

Использование TypeScript в Haunted позволяет получить максимально безопасные и предсказуемые компоненты, облегчает рефакторинг и поддержку кода, а также повышает читаемость проекта.