Функциональные компоненты против React.FC
в TypeScript: цивилизованный разговор
React и TypeScript вместе приходят в проект. TypeScript говорит: «Я буду управлять типами». React отвечает: «Я займусь рендерингом». И где-то по ходу дела кто-то спрашивает:
Следует ли использовать
React.FC
или просто типизировать функцию напрямую?
Это разумный вопрос. На первый взгляд React.FC
выглядит отполированным, официальным — даже утонченным. Будто он нальёт вашему коду бокал вина и скажет: «Давайте сделаем этот компонент элегантным». Но под поверхностью он несёт некоторые «багаж», который современные версии TypeScript почти перестали поддерживать.
Давайте посмотрим внимательнее.
Два стиля
Обычный функциональный компонент
type Props = { title: string };
function MyComponent({ title }: Props) {
return <h1>{title}</h1>;
}
Чисто, понятно и просто. Как чёрный кофе: без излишеств, просто делает свою работу.
Или, если предпочитаете стрелочные функции:
const MyComponent = ({ title }: Props) => {
return <h1>{title}</h1>;
};
Оба варианта валидны, читаемы и хорошо соответствуют современным лучшим практикам.
Вариант с React.FC
import { FC } from 'react';
type Props = { title: string };
const MyComponent: FC<Props> = ({ title }) => {
return <h1>{title}</h1>;
};
Этот вариант обёртывает компонент в обобщённый тип. Выглядит более «официально», и если вы недавно познакомились с утилитными типами в TypeScript, это может восприниматься как естественный выбор — словно вы только что получили секретный доступ. Но иногда секретные клубы идут с мелким шрифтом.
Что на самом деле делает React.FC
React.FC (сокращение от React.FunctionComponent) — это вспомогательный тип, описывающий функциональный компонент. Он предоставляет несколько предустановленных особенностей:
- По умолчанию включает проп children, хотите вы этого или нет.
- Иногда улучшает автодополнение в некоторых редакторах.
- Может чуть более явно указывать тип возвращаемого значения функции, хотя на практике это редко важно.
Это скромные удобства, которые раньше в эпоху React + TypeScript были более полезными. Но времена изменились, и сейчас эти «функции» часто мешают больше, чем помогают.
Почему он теряет популярность
Можно сказать, что React.FC — это карго-шорты TypeScript: много карманов, и почти все они не используются.
- Неявный children
Каждый компонент получает проп children, независимо от потребности. Это может привести к запутанным ошибкам, когда разработчики предполагают, что children допустимы просто потому, что так говорит тип. (Спойлер: не всегда.)
- Сложности с обобщениями (generics)
Когда вашему компоненту нужны дженерики, React.FC скорее усложняет дело, чем упрощает. Синтаксис становится громоздким, а TypeScript — менее полезным.
- Многословность без ясности
Запись const MyComponent: FC<Props>
длиннее и, возможно, менее прозрачна, чем простая типизация пропсов напрямую.
- Уже не нужна
Исходные причины для использования React.FC — поддержка редакторов, вывод типов в JSX — в основном решены улучшениями самого TypeScript. То, что было полезным обходным путём, сейчас — просто наследие.
Сравнение лицом к лицу
Особенность | function Component() | const Component: FC |
---|---|---|
Включает children? | Только если объявлен | Всегда включён |
Поддерживает generics? | Легко | Сложно, требует усилий |
Многословность? | Минимальная | Заметно больше |
Поддержка редактора? | Достаточная | Немного лучше в отдельных случаях |
Рекомендуется? | Да | Уже нет |
Рекомендуемый подход
Общее мнение сообщества простое: типизируйте пропсы напрямую. Если хотите, чтобы компонент принимал children — объявите их. Если нет — не объявляйте. Такая честность понравится вашему будущему «я».
type Props = {
title: string;
children?: React.ReactNode;
};
const MyComponent = ({ title, children }: Props) => (
<div>
<h1>{title}</h1>
{children}
</div>
);
Это явно. Это удобно поддерживать. И это не делает вид, что ваш компонент обрабатывает children, если это не так.
Бывают ли ситуации, где React.FC всё ещё уместен?
Иногда. Если вы работаете с наследуемым кодом, где React.FC широко используется, ради консистентности может быть важнее не переписывать всё. Если быстро прототипируете и не хотите заморачиваться с типизацией children, React.FC может быть коротким путём.
Но в целом, это исключения, подтверждающие правило.
В заключение
React.FC — не ошибка. Просто он больше не обязателен. Современный TypeScript упростил и сделал более предсказуемой типизацию React-компонентов без него.
Поэтому в следующий раз, когда вы возьмётесь за FC, задумайтесь — добавляете ли вы ценность или просто слой сложности. Чаще всего простая функция с типами обойдётся лучше.
В программировании — как и в жизни — ясность важнее хитрости. А меньше сюрпризов обычно означает меньше сожалений.