Современный React все больше соответствует идеалам функционального программирования.
Ежедневно мы пользуемся подходами из мира ФП, зачастую даже не подозревая об этом.
Эти паттерны плотно укоренились в сознании фронтенд-разработчиков, делая наш код значительно чище, читаемее и предсказуемее.
Вот лишь некоторые из них:
Декларативный код. Мы не говорим как рендерить, мы говорим что.
UI = f(state). Интерфейс – функция от состояния.
Композиция. Сложные компоненты собираются из простых независимых блоков.
Мемоизация. Функцию можно переиспользовать, пока данные не изменятся.
И так далее.

Программирование в функциональном стиле может быть не такой простой задачей, особенно для человека, не знакомого с этой парадигмой.
Обилие математических терминов, жесткие рамки и ограничения, непонятные формы записи и взрывающие голову рекурсии.
Но как только вы осознаете всю красоту и мощь функциональных паттернов – вы уже не сможете без них обойтись.
Сегодня мы углубимся в идеи функционального мира и рассмотрим один из классических паттернов – каррирование. Мы разберемся с тем, что это такое и как применить эти знания в React.
Каррирование
Каррирование – это процесс преобразования функции, которая принимает несколько аргументов, в набор функций, каждая из которых принимает один аргумент.
function sum(a: number, b: number) { return a + b; } function curriedSum(a: number) { return function(b: number) { return a + b; }; } curriedSum(2)(3);
Часто вместе с каррированием обсуждается "частичное применение" – фиксирование части аргументов заранее.
Эти паттерны схожи, но не идентичны.
При каррировании каждый вызов может принимать строго один аргумент, а при частичном применении – несколько.
А что в React?
В современной React-разработке компонент в виде функции является стандартом. Он принимает пропсы на вход и возвращает JSX на выходе.
Можем ли мы применить принцип каррирования к props React-компонента? Зафиксировать часть значений, а остальные передать позднее.
В этой статье мы реализуем именно принцип частичного применения. Передавать один проп или несколько – решать вам.
Предлагаю отложить все объяснения на потом и сразу взглянуть пример:
import { FC } from 'react'; function partialProps<P extends Record<string, unknown>, K extends keyof P>( Component: FC<P>, partial: Pick<P, K>, ): FC<Omit<P, K>> { return (props) => { return <Component {...partial} {...(props as P)} />; }; }
Теперь давайте подробнее рассмотрим из чего состоит данная функция:
P– общий тип пропов исходного компонента.K extends keyof P– множество ключей пропов, которые мы хотим зафиксировать.Pick<P, K>берёт изPтолько ключи изK.Omit<P, K>удаляет изPвсе ключи изK.Возвращаемым результатом этой функции будет новый компонент
FC<Omit<P, K>>, который ожидает только оставшиеся поля.Во время рендера
partialиpropsбудут склеены в общий набор пропов, соответствующий типуP.
Вот так просто у нас получилась функция частичного применения для пропов React-компонента.
Как по мне – выглядит очень лаконично, вполне в духе ФП!
Теперь пришло время рассмотреть несколько примеров того, как применить этот паттерн на практике.
Начнем с того, что перепишем изначальный пример с суммой двух чисел с использованием функции partialProps:
type Props = { a: number; b: number; }; const Sum = ({ a, b }: Props) => { return <div>{a + b}</div>; }; const PartialSum = partialProps(Component, { a: 1 }); export default function App() { return ( <div> <PartialSum b={3} /> </div> ); }
Как мы видим, компонент Sum больше не ждет, что мы передадим ему все необходимые значения сразу, а готов принимать их последовательно.
Далее рассмотрим достаточно часто случающийся случай. В вашей библиотеке компонентов наверняка есть варианты кнопок для разных ситуаций.
Цвет, размер, вариант – все это может быть сконфигурированно заранее с помощью функции partialProps.
type ButtonProps = { color: string; size: "small" | "medium" | "large"; variant: "contained" | "outlined"; onClick?: () => void; }; const Button: React.FC<ButtonProps> = ({ color, size, variant, onClick, children, }) => { const style = { backgroundColor: color }; const className = `${size} ${variant}`; return ( <button style={style} onClick={onClick} className={className} > {children} </button> ); }; const ImportantRedButton = partialProps(Button, { color: "red", size: "large", variant: "contained", }); export default function App() { return ( <ImportantRedButton onClick={() => alert("Clicked!")}> Delete </ImportantRedButton> ); };
Таких предсконфигурированных кнопок можно создать любое количество, задав им часть нужных параметров заранее.
Вот еще несколько примеров, где такая функция может быть полезна:
Предустановленный роутер / навигация.
Предварительно заполненные параметры API-запроса.
Предконфигурированные поля формы.
Преднастроенные визуальные темы.
Частичное применение параметров коллбэков.

Higher-Order Components
Если вы давно программируете на React, наверно, смогли заметить, что этот подход во многом совпадает по принципу с другим паттерном (кстати тоже из функционального программирования) — HOC (Higher‑Order Component).
Когда вы каррируете компонент — вы фактически создаете узкоспециализированный HOC, который подставляет пропсы.
С точки зрения реализации частичное применение пропсов — это частный случай HOC.
Я бы сказал, что тут нет конфликта, каждый решает свою специфическую задачу.
Однако у такого подхода есть и свои плюсы:
Простота и наглядность. Нет «магии» или сторонних эффектов.
Чистота. Нет необходимости явно указывать принимаемые параметры, как в HOC.
Строгая типизация. TypeScript сможет точно вывести какие поля остались свободными, а какие уже зафиксированы.
Заключение
Частичное применение и каррирование — это отличные паттерны, которые прекрасно ложатся на функциональную парадигму программирования в React!
Надеюсь, эта маленькая, но полезная, утилита поможет вам сделать код декларативнее и углубит ваши знания в функциональном программировании.
