Haunted — это библиотека для создания веб-компонентов на базе функциональных компонентов и хуков, вдохновлённых React, но использующая нативные возможности веб-платформы. Строгая типизация в Haunted играет ключевую роль в предотвращении ошибок на этапе разработки, обеспечивая корректность передаваемых данных и предсказуемость поведения компонентов.
В Haunted компоненты получают данные через свойства (props). Для строгой типизации важно явно указывать ожидаемый тип каждого свойства. Хотя JavaScript сам по себе динамически типизирован, интеграция с TypeScript позволяет гарантировать корректность типов.
Пример объявления компонента с типизированными свойствами:
import { component, html } from 'haunted';
interface UserCardProps {
name: string;
age: number;
isAdmin?: boolean; // необязательное свойство
}
function UserCard({ name, age, isAdmin }: UserCardProps) {
return html`
<div>
<h2>${name}</h2>
<p>Возраст: ${age}</p>
${isAdmin ? html`<strong>Администратор</strong>` : ''}
</div>
`;
}
customElements.define('user-card', component(UserCard));
Ключевые моменты:
UserCardProps задаёт строгие типы для каждого
свойства.isAdmin помечено как необязательное, что предотвращает
ошибки при отсутствии этого свойства.Haunted использует хук useState для управления
состоянием компонента. Строгая типизация состояния позволяет отслеживать
изменения типов данных, предотвращая логические ошибки.
import { useState } from 'haunted';
function Counter() {
const [count, setCount] = useState<number>(0);
const increment = () => setCount(count + 1);
return html`
<div>
<p>Счётчик: ${count}</p>
<button @click=${increment}>Увеличить</button>
</div>
`;
}
Особенности типизации:
<number> указывает, что состояние
count может быть только числом.count значение другого типа
приведёт к ошибке TypeScript.const [todos, setTodos] = useState<{ id: number; title: string; done: boolean }[]>([]);
Haunted позволяет подписываться на события через синтаксис
@event. Строгая типизация событий позволяет точно описывать
структуру данных, передаваемых в обработчик.
interface FormSubmitEventDetail {
username: string;
password: string;
}
function LoginForm() {
const handleSubmit = (event: CustomEvent<FormSubmitEventDetail>) => {
console.log(event.detail.username);
};
return html`
<form @submit=${(e: Event) => {
e.preventDefault();
handleSubmit(new CustomEvent('submit', { detail: { username: 'user', password: '1234' } }));
}}>
<input name="username" />
<input name="password" type="password" />
<button type="submit">Войти</button>
</form>
`;
}
Важные моменты:
CustomEvent<T>, где T —
тип объекта detail.Haunted поддерживает слоты, через которые можно передавать дочерние элементы. Типизация помогает определить, какие элементы допустимы:
interface CardProps {
header: string;
children?: HTMLElement[];
}
function Card({ header, children }: CardProps) {
return html`
<div class="card">
<h3>${header}</h3>
<div class="content">
${children}
</div>
</div>
`;
}
Особенности:
children типизирован как массив
HTMLElement.Для полного использования строгой типизации рекомендуется:
useState, useEffect,
useRef.strict, noImplicitAny,
strictNullChecks).Пример сложного компонента с полной типизацией:
interface TodoItem {
id: number;
text: string;
completed: boolean;
}
interface TodoListProps {
initialTodos?: TodoItem[];
}
function TodoList({ initialTodos = [] }: TodoListProps) {
const [todos, setTodos] = useState<TodoItem[]>(initialTodos);
const toggleTodo = (id: number) => {
setTodos(todos.map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo));
};
return html`
<ul>
${todos.map(todo => html`
<li @click=${() => toggleTodo(todo.id)}>
${todo.completed ? html`<s>${todo.text}</s>` : todo.text}
</li>
`)}
</ul>
`;
}
Выводы из практики:
Строгая типизация в Haunted создаёт каркас над гибкостью JavaScript, позволяя разрабатывать сложные интерфейсы с гарантией корректности данных на всех уровнях компонента.