Как типизировать компонент и пропсы в TypeScript?
Что проверяют
Знаете ли вы актуальный способ типизации React-компонентов, а не шаблон пятилетней давности. Интервьюер смотрит, как вы описываете необязательные пропсы, children, значения по умолчанию и пропсы, пробрасываемые в нативный элемент. Следом часто спрашивают, чем interface отличается от type и нужен ли React.FC.
Как отвечать
Базовый вариант: тип пропсов и аннотация параметра функции, например type ButtonProps = { label: string; variant?: "primary" | "ghost" } и function Button({ label, variant = "primary" }: ButtonProps). Дальше ключевые моменты:
- значения по умолчанию: через деструктуризацию с дефолтом.
defaultPropsдля функциональных компонентов в React 19 удалён, у классовых остался; React.FC: не ошибка, но и не обязателен. С@types/react18 он не добавляетchildrenнеявно, так что старая причина его брать ушла;children: явно, какchildren: React.ReactNode, или черезPropsWithChildren<Props>;- обёртка над нативным элементом:
ComponentProps<"button">илиComponentPropsWithoutRef<"button">, плюсOmitдля конфликтующих пропсов. В React 19refпередаётся как обычный проп,forwardRefв новых компонентах не нужен; - события:
React.ChangeEvent<HTMLInputElement>,React.MouseEvent<HTMLButtonElement>или тип всего обработчика вродеReact.ChangeEventHandler<HTMLInputElement>; - дженерик-компоненты:
function List<T>({ items, render }: { items: T[]; render: (item: T) => React.ReactNode }); - дискриминированные объединения: когда набор пропсов зависит от варианта, например
{ kind: "link"; href: string } | { kind: "button"; onClick: () => void }.
Про interface и type: для пропсов подходят оба. interface расширяется через extends и сливается при повторном объявлении, type умеет объединения и сопоставленные типы.
Где спотыкаются
Советуют defaultProps для функциональных компонентов. В React 19 это уже не работает.
Пишут any для обработчиков и children, теряя весь смысл типизации.
Путают React.ReactNode и JSX.Element: второй не принимает строку, null и массив, поэтому для children слишком узкий.