Почему стоит использовать TypeScript с React?
TypeScript расширяет возможности React следующим образом:
- Статическая проверка типов для пропсов, состояния и контекста
- Подсказки автозавершения и рефакторинга в IDE
- Раннее выявление ошибок во время разработки
Если вы новичок в React, сначала ознакомьтесь с нашим учебником React.
Начало работы
Создайте новое приложение React + TypeScript с помощью Vite:
Пример
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run dev
Ваш файл tsconfig.json должен включать следующие рекомендуемые настройки компилятора:
Пример
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "Node",
"jsx": "react-jsx",
"strict": true,
"skipLibCheck": true,
"noEmit": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src"]
}
Примечание: Оставляйте настройку strict включенной для лучшей защиты типов.
Показанные опции хорошо работают с Vite и Create React App.
Типизация компонентов
Определите пропсы с помощью TypeScript и используйте их в функциональном компоненте:
Пример
// Greeting.tsx
type GreetingProps = {
name: string;
age?: number;
};
export function Greeting({ name, age }: GreetingProps) {
return (
<div>
<h2>Привет, {name}!</h2>
{age !== undefined && <p>Вам {age} лет</p>}
</div>
);
}
Распространённые шаблоны
Безопасные события
Типизируйте обработчики событий для ввода и кнопок:
Пример
// Изменение ввода
function NameInput() {
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
console.log(e.target.value);
}
return <input onChange={handleChange} />;
}
// Нажатие кнопки
function SaveButton() {
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
e.preventDefault();
}
return <button onClick={handleClick}>Сохранить</button>;
}
Типизация состояния с помощью useState
Используйте явные типы для чисел, объединений и нулевых значений:
Пример
const [count, setCount] = React.useState<number>(0);
const [status, setStatus] = React.useState<'idle' | 'loading' | 'error'>('idle');
type User = { id: string; name: string };
const [user, setUser] = React.useState<User | null>(null);
useRef с элементами DOM
Типизируйте ссылки на элементы DOM для безопасного доступа к свойствам:
Пример
function FocusInput() {
const inputRef = React.useRef<HTMLInputElement>(null);
return <input ref={inputRef} onFocus={() => inputRef.current?.select()} />;
}
Типизация дочерних элементов
Принимайте дочерние элементы с типом React.ReactNode:
Пример
type CardProps = { title: string; children?: React.ReactNode };
function Card({ title, children }: CardProps) {
return (
<div>
<h2>{title}</h2>
{children}
</div>
);
}
Вспомогательные функции для запросов с обобщенными типами
Используйте обобщения для типизации ответов API:
Пример
async function fetchJson<T>(url: string): Promise<T> {
const res = await fetch(url);
if (!res.ok) throw new Error('Ошибка сети');
return res.json() as Promise<T>;
}
// Использование внутри асинхронной функции/события компонента
async function loadPosts() {
type Post = { id: number; title: string };
const posts = await fetchJson<Post[]>("/api/posts");
console.log(posts);
}
Минимальный контекст и пользовательский хук
Предоставляйте небольшой, типизированный контекст и вспомогательный хук:
Пример
type Theme = 'light' | 'dark';
const ThemeContext = React.createContext<{ theme: Theme; toggle(): void } | null>(null);
function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = React.useState<Theme>('light');
const value = { theme, toggle: () => setTheme(t => (t === 'light' ? 'dark' : 'light')) };
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
}
function useTheme() {
const ctx = React.useContext(ThemeContext);
if (!ctx) throw new Error('useTheme должен использоваться внутри ThemeProvider');
return ctx;
}
Типы Vite для TypeScript: добавьте глобальные типы Vite, чтобы избежать отсутствия определений.
Пример
// src/vite-env.d.ts
/// <reference types="vite/client" />
Альтернативно, добавьте в tsconfig.json:
Пример
{
"compilerOptions": {
"types": ["vite/client"]
}
}
О React.FC: Используйте непосредственно типизированные функциональные компоненты.
React.FC является необязательным; он неявно добавляет children, но не обязателен.
Необязательные baseUrl и paths: Эти параметры упрощают импорт, если поддерживаются вашим пакетом сборки.
Пример
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
Конфигурируйте только в том случае, если ваше окружение (например, Vite, tsconfig-paths) настроено для псевдонимов путей.