Как правильно типизировать `children` проп в React с TypeScript

Выжимка статьи: How to type React children correctly in TypeScript

Как правильно типизировать `children` проп в React с TypeScript

Типизация пропса children в React может быть сложной задачей из-за разнообразия поддерживаемых типов и "парадокса выбора" среди нескольких доступных опций. Проп children позволяет компоненту получать и обрабатывать содержимое, переданное между его открывающим и закрывающим тегами JSX. Это содержимое может быть строками, другими JSX-элементами, JavaScript-выражениями или даже функциями, что демонстрирует широкий спектр его возможностей.

Однако ручная типизация всех этих вариантов, таких как string | JSX.Element | JSX.Element[] | () => JSX.Element, не рекомендуется, поскольку она не учитывает многие другие renderable значения, включая фрагменты, порталы, null, undefined и boolean. Вместо этого, для гибкой и полной типизации children следует использовать универсальный тип React.ReactNode, который охватывает практически все, что React может отобразить.

type Props = {
  children: React.ReactNode;
}

Для компонентов, которые уже имеют свои собственные пропсы и которым нужно просто добавить children, React предоставляет удобный тип React.PropsWithChildren<P>. Он объединяет существующие пропсы с опциональным полем children: React.ReactNode.

import { PropsWithChildren } from 'react';

type FooProps = {
  name: 'foo';
}

const Foo = (props: PropsWithChildren<FooProps>) => {
    return props.children;
}

Кроме того, React.ComponentProps<typeof SomeComponent> крайне полезен для создания обёрточных компонентов, позволяя автоматически наследовать все пропсы базового компонента, включая children, обеспечивая высокую степень переиспользуемости и типобезопасности. Более специфичные типы, такие как React.ReactElement или JSX.Element, также могут использоваться, но они представляют собой один React-элемент и не допускают falsy значений.

В современных версиях React (начиная с React 18) React.FC (или FunctionComponent) больше не включает children автоматически, что требует его явного объявления в интерфейсе пропсов. Этот подход поощряет большую ясность и предсказуемость в типизации компонентов. Аналогично, в React 19 типизация компонентов, принимающих children и refs, стала более явной, требуя их ручного указания в типе пропсов.

Обёрточные компоненты, использующие TypeScript, могут значительно улучшить типобезопасность, особенно при работе со сложными структурами children, гарантируя, что все необходимые свойства присутствуют и правильно типизированы. В конечном итоге, понимание React.ReactNode и переход к явному объявлению children превращает его типизацию из догадок в обдуманный и поддерживаемый выбор.

Оригинал статьи: How to type React children correctly in TypeScript