React Hook Form泛型单选按钮组件TypeScript类型报错求助
泛型单选按钮结合React Hook Form的TypeScript类型问题排查
问题背景
已实现可正常运行的泛型单选按钮组件,结合React Hook Form做表单校验时出现TypeScript类型报错,移除泛型则功能正常,需排查解决。
组件代码
import React, { ReactNode } from 'react'; import styled from 'styled-components/native'; export interface RadioButtonProp<T> { data: T[] value?: T render: (item: T, index?: number) => ReactNode } export const RadioButton = <T,>(props: RadioButtonProp<T>) => { const { data, render } = props return ( <Container> {data.map((item: T, index: number) => { return <RowContainer key={index.toString()}>{render(item, index)}</RowContainer> })} </Container> ) } const Container = styled.View` margin-top: 5px; ` const RowContainer = styled.View``
React Hook Form封装代码
import { FieldValues, UseControllerProps, Controller } from "react-hook-form"; import { RadioButton, RadioButtonProp } from './RadioButton'; export type RfhBadioButtonProp<T extends FieldValues> = RadioButtonProp<T> & UseControllerProps<T> export const RhfRadioButton = <T extends FieldValues>(props: RfhBadioButtonProp<T>) => { return ( <Controller rules={props.rules} control={props.control} name={props.name} render={({ field }) => ( <> <RadioButton data={props.data} render={props.render} value={props.value || field.value} /> </> )} /> ) }
表单使用代码
// 假设Fruit为表单类型,useForm初始化示例: type Fruit = { fruits: string; }; const { control } = useForm<Fruit>(); <RhfRadioButton control={control} name={'fruits'} data={['Apple', 'Oranges', 'Banana']} render={renderRadioButtons} value={fruit} />
TypeScript报错信息
Type 'Control<Fruit, any>' is not assignable to type 'Control<FieldValues, any>'. The types of '_options.resolver' are incompatible between these types. Type 'Resolver<Fruit, any> | undefined' is not assignable to type 'Resolver<FieldValues, any> | undefined'. Type 'Resolver<Fruit, any>' is not assignable to type 'Resolver<FieldValues, any>'
问题原因
原封装代码的泛型约束错误:将单选按钮的选项类型直接约束为FieldValues(表单整体类型),导致React Hook Form的Control<表单类型>与Control<选项类型>类型不兼容,触发类型校验报错。
解决方案
拆分泛型,分别指定表单整体类型和单选选项类型,修正封装代码如下:
import { FieldValues, UseControllerProps, Controller } from "react-hook-form"; import { RadioButton, RadioButtonProp } from './RadioButton'; // 拆分泛型:T为表单FieldValues类型,V为单选选项类型 export type RhfRadioButtonProp<T extends FieldValues, V> = RadioButtonProp<V> & Omit<UseControllerProps<T>, 'render'>; export const RhfRadioButton = <T extends FieldValues, V>(props: RhfRadioButtonProp<T, V>) => { return ( <Controller rules={props.rules} control={props.control} name={props.name} render={({ field }) => ( <RadioButton data={props.data} render={props.render} value={props.value ?? field.value} /> )} /> ) }
关键修改说明
- 泛型拆分:新增泛型
V用于定义单选选项的类型,T保留为表单整体的FieldValues类型,解决类型不匹配问题。 - Omit冗余属性:通过
Omit<UseControllerProps<T>, 'render'>移除UseControllerProps中的render属性,避免与组件自身的render属性冲突。 - 空值处理优化:用
??替代||,更严谨处理0、''等 falsy 值场景。
修改后,表单中使用组件时无需手动指定泛型,TypeScript会自动推断T(表单类型)和V(选项类型),类型校验正常通过。
内容的提问来源于stack exchange,提问作者EI-01
相关产品推荐
相关产品推荐

