Короткий ответ: если в React + TypeScript ломается кастомный компонент, почти всегда проблема в props. Нужно явно описать, какие свойства компонент принимает, добавить children, если внутри есть вложенный контент, и расширить HTML-атрибуты, если компонент должен вести себя как обычная кнопка, ссылка или input
Типичная ошибка выглядит так:
Property 'children' does not exist on type ...
или:
Type '{ onClick: ... }' is not assignable to type ...
Базовый компонент с props
Плохо:
export function Badge(props) {
return <span>{props.label}</span>;
}
В TypeScript лучше так:
type BadgeProps = {
label: string;
tone?: "success" | "warning" | "danger";
};
export function Badge({ label, tone = "success" }: BadgeProps) {
return <span className={`badge badge-${tone}`}>{label}</span>;
}
Теперь TypeScript знает, что label обязателен, а tone может быть только одним из трех значений
Использование:
<Badge label="Опубликовано" tone="success" />
Если написать tone="blue", TypeScript поймает ошибку
Если нужен children
Если компонент принимает вложенный контент, добавьте children:
import type { ReactNode } from "react";
type CardProps = {
title: string;
children: ReactNode;
};
export function Card({ title, children }: CardProps) {
return (
<section className="card">
<h2>{title}</h2>
<div>{children}</div>
</section>
);
}
Использование:
<Card title="Профиль">
<p>Данные пользователя</p>
</Card>
Без children TypeScript будет честно ругаться: вы передаете вложенный JSX, а тип компонента такого свойства не обещает
Если компонент должен быть как button
Частая проблема: кастомная кнопка не принимает onClick, disabled, type и другие стандартные атрибуты
Решение:
import type { ButtonHTMLAttributes, ReactNode } from "react";
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
variant?: "primary" | "secondary";
children: ReactNode;
};
export function Button({
variant = "primary",
children,
className,
...rest
}: ButtonProps) {
return (
<button className={`btn btn-${variant} ${className ?? ""}`} {...rest}>
{children}
</button>
);
}
Теперь работает:
<Button type="button" disabled={false} onClick={() => alert("click")}>
Сохранить
</Button>
Ключевая идея: если ваш компонент оборачивает настоящий HTML-элемент, типизируйте стандартные атрибуты этого элемента
Если нужен ref
Обычный prop ref не проходит в функциональный компонент автоматически. Для ref используйте forwardRef:
import { forwardRef } from "react";
import type { ButtonHTMLAttributes } from "react";
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
variant?: "primary" | "secondary";
};
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ variant = "primary", className, ...rest }, ref) => {
return (
<button
ref={ref}
className={`btn btn-${variant} ${className ?? ""}`}
{...rest}
/>
);
}
);
Button.displayName = "Button";
Это нужно для форм, фокуса, UI-библиотек и компонентов, которые должны отдавать ссылку на DOM-элемент
Частые ошибки
Первая ошибка — писать props как any. Ошибка исчезает, но польза TypeScript тоже исчезает
Вторая ошибка — забыть children. Если компонент используется как контейнер, children должен быть в типе
Третья ошибка — не передать ...rest в настоящий HTML-элемент. Тогда onClick формально принимается, но не работает в DOM
Четвертая ошибка — использовать React.FC только ради children. Сейчас чаще проще явно описать children: ReactNode, чтобы тип был виден и контролируем
Самопроверка
Создайте кастомный Button, передайте в него onClick, disabled, type="submit" и вложенный текст. Если TypeScript не ругается, а кнопка работает в браузере, базовая проблема решена
Потом намеренно передайте неправильный variant="blue". Если TypeScript ловит ошибку, ваши props действительно типизированы, а не превращены в any
Что почитать дальше по TypeScript
Если нужен общий маршрут по теме, откройте рубрику TypeScript. Для соседних задач пригодятся эти разборы:
- App.tsx: что это за файл и как добавить TypeScript в React
- Create React App и TypeScript: как установить, запустить и проверить
- React и TypeScript: как настроить и использовать в проекте
- TypeScript в React: props, state и события



