Функциональные компоненты против React.FC в TypeScript: цивилизованный разговор

Понимание эволюции типизации TypeScript в React-компонентах

Функциональные компоненты против 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: много карманов, и почти все они не используются.

  1. Неявный children

Каждый компонент получает проп children, независимо от потребности. Это может привести к запутанным ошибкам, когда разработчики предполагают, что children допустимы просто потому, что так говорит тип. (Спойлер: не всегда.)

  1. Сложности с обобщениями (generics)

Когда вашему компоненту нужны дженерики, React.FC скорее усложняет дело, чем упрощает. Синтаксис становится громоздким, а TypeScript — менее полезным.

  1. Многословность без ясности

Запись const MyComponent: FC<Props> длиннее и, возможно, менее прозрачна, чем простая типизация пропсов напрямую.

  1. Уже не нужна

Исходные причины для использования 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, задумайтесь — добавляете ли вы ценность или просто слой сложности. Чаще всего простая функция с типами обойдётся лучше.

В программировании — как и в жизни — ясность важнее хитрости. А меньше сюрпризов обычно означает меньше сожалений.

Categories