Solid.js — это высокоэффективный фреймворк для создания пользовательских интерфейсов с использованием реактивных вычислений и минимальной абстракции. Одним из важных аспектов разработки в Solid.js является типизация компонентов, что позволяет повысить надежность кода, улучшить поддержку и ускорить разработку. В этой главе рассмотрим, как эффективно использовать TypeScript для типизации компонентов в Solid.js.
В Solid.js компоненты являются функциями, которые могут принимать пропсы (параметры) и возвращать разметку. Типизация этих пропсов и состояния компонентов — ключевая часть работы с TypeScript в Solid.js.
import { createSignal } from "solid-js";
type Props = {
title: string;
};
const MyComponent: React.FC<Props> = (props) => {
const [count, setCount] = createSignal(0);
return (
<div>
<h1>{props.title}</h1>
<button onCl ick={() => setCount(count() + 1)}>{count()}</button>
</div>
);
};
В этом примере компонента MyComponent используется тип
Props, который указывает, что проп title
должен быть строкой. Это позволяет IDE и TypeScript выявить ошибки,
связанные с неправильным типом данных на этапе разработки.
createSignal с типамиcreateSignal — это базовый хук для работы с реактивными
значениями в Solid.js. Для корректной работы с типами, важно указывать
тип данных для сигнала.
const [count, setCount] = createSignal<number>(0);
В данном случае createSignal<number>(0) явно
указывает, что сигнал count будет хранить значение типа
number.
JSX.IntrinsicElementsВ Solid.js компоненты могут быть типизированы с использованием
стандартных HTML-элементов. Если нужно добавить поддержку типизации для
стандартных атрибутов HTML, можно использовать интерфейсы из библиотеки
Solid.js, такие как JSX.IntrinsicElements.
type ButtonProps = JSX.IntrinsicElements["button"];
const MyButton: React.FC<ButtonProps> = (props) => {
return <button {...props} />;
};
Здесь JSX.IntrinsicElements["button"] позволяет
компоненту MyButton наследовать типы для всех атрибутов
стандартного HTML-элемента button, что даёт возможность
использовать любые стандартные атрибуты, такие как onClick,
disabled, style и другие.
Когда компонент требует более сложной структуры пропсов, например, вложенные объекты или массивы, типизацию можно сделать с использованием вложенных типов.
type User = {
id: number;
name: string;
};
type Props = {
user: User;
isActive: boolean;
};
const UserProfile: React.FC<Props> = ({ user, isActive }) => {
return (
<div>
<h2>{user.name}</h2>
{isActive ? <span>Active</span> : <span>Inactive</span>}
</div>
);
};
Здесь компонент UserProfile принимает проп
user, который имеет сложную структуру с двумя полями:
id и name, а также проп isActive,
который указывает, активен ли пользователь.
В Solid.js можно использовать не только сигналы, но и вычисляемые значения, которые зависят от других реактивных данных. Типизация этих значений также важна для обеспечения правильной работы приложения.
const [count, setCount] = createSignal<number>(0);
const doubleCount = () => count() * 2;
const MyComponent: React.FC = () => {
return (
<div>
<p>Count: {count()}</p>
<p>Double Count: {doubleCount()}</p>
<button onCl ick={() => setCount(count() + 1)}>Increment</button>
</div>
);
};
Здесь doubleCount — это вычисляемое значение, которое
зависит от сигнала count. TypeScript сам определяет тип
возвращаемого значения, но, если необходимо, можно явно указать тип,
если вычисление сложное.
Типизация событий в Solid.js также важна для корректного использования обработчиков событий. В отличие от других фреймворков, Solid.js не использует синтетические события как React. События в Solid.js типизируются напрямую с помощью стандартных типов событий браузера.
const MyComponent: React.FC = () => {
const handleClick = (event: MouseEvent) => {
console.log("Button clicked", event);
};
return <button onCl ick={handleClick}>Click me</button>;
};
Здесь MouseEvent — это стандартный тип события,
доступный в DOM. TypeScript гарантирует, что переменная
event будет иметь тип MouseEvent, что
позволяет получить доступ к его свойствам, например,
event.clientX, event.clientY и другим.
Solid.js предоставляет возможность использовать контексты для передачи данных через дерево компонентов. Типизация контекста позволяет передавать данные безопасно и без ошибок.
import { createContext, useContext } from "solid-js";
type UserContextType = {
user: User;
setUser: (user: User) => void;
};
const UserContext = createContext<UserContextType | undefined>(undefined);
const UserProvider: React.FC = (props) => {
const [user, setUser] = createSignal<User | null>(null);
return (
<UserContext.Provider value={{ user: user(), setUser }}>
{props.children}
</UserContext.Provider>
);
};
const UserProfile: React.FC = () => {
const context = useContext(UserContext);
if (!context) return <div>Loading...</div>;
return (
<div>
<h2>{context.user?.name}</h2>
<button onCl ick={() => context.setUser({ id: 1, name: "John Doe" })}>
Set User
</button>
</div>
);
};
В этом примере создается контекст UserContext, который
типизирован с помощью интерфейса UserContextType.
Компоненты, использующие этот контекст, могут безопасно извлекать и
изменять данные пользователя.
В некоторых случаях может потребоваться использование универсальных типов (generic), чтобы компоненты могли работать с различными типами данных, не теряя типовую безопасность.
type ButtonProps<T> = {
label: string;
onClick: (value: T) => void;
};
function Button<T>(props: ButtonProps<T>) {
return <button onCl ick={() => props.onClick(props.label as any)}>{props.label}</button>;
}
<Button<number> label="Click Me" onCl ick={(value) => console.log(value)} />
В этом примере компонент Button использует универсальный
тип T для обработки различных типов данных в пропсе
onClick. TypeScript автоматически типизирует компонент на
основе передаваемых параметров, обеспечивая безопасное
использование.
Типизация компонентов в Solid.js с использованием TypeScript играет важную роль в повышении качества и устойчивости кода. Правильная типизация пропсов, сигналов, вычисляемых значений, событий и контекстов помогает минимизировать количество ошибок и улучшает поддержку кода. Рекомендуется использовать строгую типизацию во всех частях приложения, чтобы получить все преимущества TypeScript, такие как автодополнение, статический анализ и устранение ошибок на этапе разработки.