Haunted — это современная библиотека для создания веб-компонентов на базе Web Components с использованием реактивного подхода, вдохновленного React Hooks. Одним из важных аспектов разработки масштабируемых приложений на Haunted является строгая и продвинутая типизация, особенно при использовании TypeScript. Она обеспечивает безопасность кода, предотвращает ошибки на этапе компиляции и улучшает читаемость проекта.
В Haunted компоненты реализуются как функции, возвращающие шаблоны
html. Стандартная сигнатура компонента выглядит так:
import { html } from 'haunted';
function MyComponent(props: { title: string }) {
return html`<h1>${props.title}</h1>`;
}
Ключевые моменты:
props всегда типизируются как объект. Это позволяет
строго контролировать входные данные.html возвращает тип
TemplateResult, но для более строгой типизации
рекомендуется явное указание:import { TemplateResult, html } from 'haunted';
function MyComponent(props: { title: string }): TemplateResult {
return html`<h1>${props.title}</h1>`;
}
Haunted поддерживает декларацию свойств с использованием
@property декоратора или через props объекта.
Для TypeScript важно явно определять типы:
import { component, html } from 'haunted';
import { property } from 'lit/decorators.js';
class Counter extends HTMLElement {
@property({ type: Number }) count = 0;
}
customElements.define('my-counter', Counter);
Особенности:
type указывает, как значение будет конвертироваться при
присвоении свойства.string вместо number будет ошибкой на этапе
компиляции.interface CounterProps {
count: number;
onIncrement?: () => void;
}
Haunted использует хуки, аналогичные React, такие как
useState, useEffect и useReducer.
Типизация этих хуков позволяет избегать неожиданных ошибок:
import { useState } from 'haunted';
function CounterComponent() {
const [count, setCount] = useState<number>(0);
return html`
<button @click=${() => setCount(count + 1)}>Increment: ${count}</button>
`;
}
Ключевые моменты:
useState<Type>(initialValue) позволяет явно
указать тип состояния.useReducer<ReducerType>(reducer, initialState)
требует явной типизации как состояния, так и экшенов:type Action = { type: 'increment' } | { type: 'decrement' };
function reducer(state: number, action: Action) {
switch (action.type) {
case 'increment': return state + 1;
case 'decrement': return state - 1;
}
}
const [count, dispatch] = useReducer<number, Action>(reducer, 0);
Haunted позволяет подписываться на события через шаблон. Для строгой типизации событий рекомендуется использовать Generic-типизацию для кастомных событий:
interface MyEventDetail {
value: string;
}
function InputComponent() {
const handleChange = (e: CustomEvent<MyEventDetail>) => {
console.log(e.detail.value);
};
return html`<input @change=${(e: CustomEvent<MyEventDetail>) => handleChange(e)} />`;
}
Особенности:
CustomEvent<T> позволяет TypeScript понимать
структуру объекта detail.Haunted поддерживает передачу детей и слотов. Для строгой типизации
удобно использовать children с типом
TemplateResult | TemplateResult[]:
interface CardProps {
title: string;
children?: TemplateResult | TemplateResult[];
}
function Card({ title, children }: CardProps): TemplateResult {
return html`
<div class="card">
<h2>${title}</h2>
<div class="content">${children}</div>
</div>
`;
}
Ключевые моменты:
children часто используют для вложенных компонентов или
динамического контента.Haunted позволяет создавать собственные хуки. Их типизация особенно важна для повторного использования:
import { useState, useEffect } from 'haunted';
function useCounter(initial: number) {
const [count, setCount] = useState<number>(initial);
useEffect(() => {
console.log(`Count: ${count}`);
}, [count]);
return { count, increment: () => setCount(count + 1) };
}
function CounterComponent() {
const { count, increment } = useCounter(0);
return html`<button @click=${increment}>${count}</button>`;
}
Особенности:
{ count: number; increment: () => void }.Haunted часто используется совместно с Lit для расширенной
функциональности. В таком случае строгая типизация становится особенно
важной для интеграции с Lit-декораторами, типизированными событиями и
TemplateResult. Например:
import { html, TemplateResult } from 'lit';
import { property } from 'lit/decorators.js';
class LitHauntedComponent extends HTMLElement {
@property({ type: String }) name = '';
render(): TemplateResult {
return html`<p>Hello, ${this.name}</p>`;
}
}
Особенности:
Продвинутая типизация в Haunted позволяет строить безопасные, предсказуемые и масштабируемые веб-компоненты, объединяя возможности реактивного подхода и строгую проверку типов, что делает разработку более структурированной и надежной.