Создание React‑проекта с TypeScript

О чём эта статья
Эта статья шаг за шагом показывает, как создать и настроить React‑проект с TypeScript, как типизировать компоненты, пропсы, state и события. Включены практические примеры, советы при миграции, чек‑листы для разработчиков и альтернативные подходы.
Важно: TypeScript не выполняет код в рантайме — это инструмент статической проверки типов и разработки. Он улучшает качество кода и опыт разработки, но не заменяет тестирование и линтинг.
Почему TypeScript в React полезен
JavaScript — слаботипный язык, и ошибки типов часто обнаруживаются только при исполнении. TypeScript вводит систему типов поверх JavaScript, что помогает:
- обнаруживать ошибки на этапе компиляции;
- улучшать автодополнение и навигацию по коду в IDE;
- формализовать контракты компонентов через типы и интерфейсы.
При этом есть компромисс: иногда требуется писать дополнительный «боилерплейт» при типизации сложных случаев.
Создание React‑проекта с TypeScript
Самый простой способ — создать проект с шаблоном TypeScript через create-react-app:
npx create-react-app app-name --template typescriptЕсли у вас уже есть приложение на React, можно добавить TypeScript в проект:
npm install --save typescript @types/node @types/react @types/react-dom @types/jestПосле установки поменяйте расширения файлов компонентов на .tsx и начните добавлять типы.
Проблема: “React refers to a UMD global, but the current file is a module”
Иногда при переименовании в .tsx вы увидите ошибку о глобальном React. Решения:
- Явно импортировать React в файле:
import React from "react";- Или настроить tsconfig.json и установить jsx в react-jsx (рекомендуется для нового кода):
{
"compilerOptions": {
"jsx": "react-jsx",
"target": "es6",
"module": "esnext"
}
}Полный список опций смотрите в официальной документации TypeScript.
Как писать функциональный компонент в TypeScript
Функциональные компоненты в TypeScript записываются так же, как в JavaScript, но при желании можно добавить аннотацию возвращаемого типа:
export default function Greetings() {
return (
Hello world
);
}С аннотацией возвращаемого типа:
export default function Greetings(): JSX.Element {
return (
Hello world
);
}TypeScript проверит, что компонент возвращает допустимый JSX.Element.
Пропсы компонентов и их типизация
Пропсы можно типизировать прямо в сигнатуре функции или вынести в отдельный тип/интерфейс.
Inline‑тип:
function Greetings({ name }: { name: string }) {
return (
Hello {name}
);
}Вынесенный тип:
type GreetingsProps = {
name: string;
};
function Greetings({ name }: GreetingsProps) {
return (
Hello {name}
);
}Если планируете экспортировать и расширять типы, используйте interface:
export interface GreetingsProps {
name: string;
}Расширение интерфейса:
import { GreetingsProps } from './Greetings';
interface WelcomeProps extends GreetingsProps {
time: string;
}
function Welcome({ name, time }: WelcomeProps) {
return (
Good {time}, {name}!
);
}Необязательные пропсы обозначаются знаком вопроса:
interface GreetingsProps {
name?: string;
}Если пропс не передан, TypeScript не будет ругаться.
Состояние (useState) и его типизация
При простых начальных значениях TypeScript может вывести тип автоматически:
const [customerName, setCustomerName] = useState("");Когда начальное значение отсутствует или может быть null, указывайте тип явно:
const [customerName, setCustomerName] = useState("");
const [age, setAge] = useState(0);
const [isSubscribed, setIsSubscribed] = useState(false); Для сложных объектов используйте интерфейс:
interface ICustomer {
customerName: string;
age: number;
isSubscribed: boolean;
}
const [customer, setCustomer] = useState({
customerName: "Jane",
age: 10,
isSubscribed: false
}); Если состояние может быть null в начале, применяйте объединение с null:
const [profile, setProfile] = useState(null); События в React и их типы
React экспортирует типы событий, которые помогают корректно типизировать обработчики.
Пример некорректно типизированного компонента (JavaScript):
import { useState } from 'react';
export default function Login() {
const [email, setEmail] = useState('');
const handleChange = (event) => {
setEmail(event.target.value);
};
const handleClick = (event) => {
console.log('Submitted!');
};
return (
);
}Типизированный пример — вариант с ChangeEvent:
import { ChangeEvent, useState } from 'react';
export default function Login() {
const [email, setEmail] = useState('');
const handleChange = (event: ChangeEvent) => {
setEmail(event.target.value);
};
const handleClick = (event: React.MouseEvent) => {
console.log('Submitted!');
};
return (
);
} Альтернатива — типизировать сам обработчик через ChangeEventHandler / MouseEventHandler:
import { ChangeEventHandler, MouseEventHandler, useState } from 'react';
const handleChange: ChangeEventHandler = (event) => {
setEmail(event.currentTarget.value);
};
const handleClick: MouseEventHandler = (event) => {
console.log('Submitted!');
}; Совет: для больших форм используйте библиотеки, которые уже поддерживают TypeScript (Formik, React Hook Form) и схемы валидации (Zod, Yup).
Когда TypeScript даёт наибольшую пользу и когда он может мешать
Когда стоит использовать TypeScript:
- крупные проекты с множеством компонентов и командой разработчиков;
- код, который поддерживается длительное время;
- важна безопасность API между слоями (компоненты, хранилище, бэкенд).
Когда TypeScript может казаться излишним:
- маленькие одноразовые скрипты или прототипы;
- когда дедлайн и обучение команды ещё не завершено;
- при частых экспериментальных изменениях, где типы часто ломают быстро меняющийся код.
Мини‑методология миграции существующего проекта на TypeScript
- Установите зависимости: typescript и @types/* для используемых пакетов.
- Создайте tsconfig.json и включите incremental и allowJs: true для плавной миграции.
- Переименуйте по одной папке .js → .tsx и исправляйте ошибки типов постепенно.
- Добавьте строгие правила постепенно: сначала “noImplicitAny”: false, затем включайте строгие опции.
- Интегрируйте линтер и форматер (ESLint с плагином TypeScript, Prettier).
- Пишите типы для публичных интерфейсов и пропсов в первую очередь.
Чек‑лист для ролей
Разработчик:
- Добавил/обновил tsconfig.json.
- Переименовал файлы и исправил критические ошибки типов.
- Написал интерфейсы для пропсов и внешних API.
- Добавил типы для useState и обработчиков событий.
Код‑ревьювер:
- Проверил корректность интерфейсов и отсутствие any без причины.
- Убедился, что публичные типы документированы.
- Оценил влияние изменений на потребителей компонента.
Техлид:
- Установил стратегию миграции и целевые опции компилятора.
- Контролирует включение строгих опций поэтапно.
- Проверяет интеграцию с CI и сборкой.
Snippets и шпаргалка по типам (cheat sheet)
- Типизация пропсов: type Props = { a: string; b?: number };
- useState с объектом: const [s, setS] = useState
(initial); - Обработчик input: (e: ChangeEvent
) => void - Кнопка: React.MouseEvent
- Ref на элемент: useRef
(null)
Альтернативы TypeScript
- PropTypes — простая валидация в рантайме (подходит для небольших проектов).
- Flow — статическая типизация от Facebook (реже используется сейчас).
- Runtime‑валидация (Zod/Yup) — полезна для схем данных и валидации вне типов.
Модели мышления и эвристики
- Типизируйте API на границе модулей: пропсы, контексты, публичные функции.
- Начинайте с поверхностных типов и уточняйте их по мере необходимости.
- Избегайте подавления ошибок через any — используйте // TODO с задачей на последующую типизацию.
Decision flow (простая диаграмма выбора)
flowchart TD
A[Проект новый?] -->|Да| B[Использовать шаблон TypeScript]
A -->|Нет| C[Есть память времени на миграцию?]
C -->|Да| D[Пошаговая миграция: allowJs -> .tsx -> усиление строгих правил]
C -->|Нет| E[Оставить JS, добавить типы по мере необходимости или использовать PropTypes]Когда TypeScript может не помочь (примеры неудач)
- Ошибки логики (не типовые) TypeScript не поймает — нужны тесты.
- Некорректные типы внешних API: если бэкенд возвращает неожиданные структуры, статическая типизация без валидации рантайма даст ложное ощущение безопасности.
Краткая памятка по ошибкам и их решениям
- “JSX element type ‘X’ does not have any construct or call signatures” — проверьте экспорт/импорт компонента и расширение файла.
- “Property ‘foo’ does not exist on type ‘Bar’” — обновите интерфейс/тип или корректно сприньте преобразование данных.
- Неправильное использование any — фиксируйте в ревью и заменяйте уточняющими типами.
1‑строчный глоссарий
- TypeScript — надстройка над JavaScript с системой типов;
- JSX.Element — тип возвращаемого значения функционального React‑компонента;
- Generics — обобщённые типы, например useState
; - Interface / type — способы объявления структур типов;
- Props — входные данные компонента;
- useState — хук для локального состояния.
Сводка
TypeScript делает React‑разработку более надёжной и предсказуемой, особенно в средних и крупных проектах. Начните с шаблона при новом проекте или внедряйте поэтапно в существующий код. Комбинация TypeScript, тестов и линтинга даёт наилучший результат по качеству и поддерживаемости кода.
Важно: не забывайте про интеграцию с CI и документацию публичных типов.
Краткое завершение и рекомендации:
- Для новых проектов используйте create-react-app с –template typescript или Vite + TypeScript.
- Для существующих проектов мигрируйте по шагам, не включая сразу все строгие опции.
- Типизируйте границы модулей в первую очередь: пропсы, контексты, API.
Спасибо за чтение. Удачной миграции и безопасной разработки!
Похожие материалы
Find My Device в Windows 11 — включение и поиск
Шаблоны автоответа «Вне офиса» и практические советы
Подпись в Outlook: шаблон и настройка
Объединение ячеек в Excel: & и CONCAT
Как поделиться экраном в Zoom