React/TypeScript中含...rest的forwardRef组件类型检查问题解决
问题根因
自定义的字符串索引签名[rest: string]: unknown会和forwardRef内部的类型映射逻辑冲突:forwardRef会通过Pick工具类型处理传入的Props接口,遇到宽泛的字符串索引时,会丢失显式声明属性的required修饰符,最终导致必填的label属性不再做强制校验。
移除forwardRef时类型校验正常,是因为普通函数组件直接读取接口类型做参数校验,不会走这层类型映射逻辑。
推荐解决方案
不要使用无约束的字符串索引签名透传属性,直接继承React内置的原生元素属性类型,既可以保留透传属性的完整类型提示,又不会丢失自定义Props的校验规则:
import React from 'react' interface InputWithLabelProps extends React.InputHTMLAttributes<HTMLInputElement> { label: string } const InputWithLabel = React.forwardRef<HTMLInputElement, InputWithLabelProps>( ({ label, ...rest }, ref) => ( <> <label htmlFor="field">{label}</label> <input id="field" ref={ref} {...rest} /> </> ), ) export default InputWithLabel
这个写法的优势:
label的必填约束会被TS正常识别,使用组件时漏传会直接抛出类型错误- 透传给
input元素的rest属性会自动获得原生输入框的完整类型校验,传type、onChange、disabled、placeholder等原生属性时都会有正确的类型提示和校验,类型安全度远高于自定义的unknown索引签名 - 推导得到的组件类型完全符合预期,不会出现属性丢失的问题
特殊场景兼容方案
如果你的rest属性不是透传给原生input元素,确实需要接收任意自定义属性,可以通过交叉类型降低索引签名的优先级,避免覆盖显式声明的属性约束:
import React from 'react' type WithSafeIndex<T> = T & { [key: string]: unknown } interface InputWithLabelProps { label: string } const InputWithLabel = React.forwardRef<HTMLInputElement, WithSafeIndex<InputWithLabelProps>>( ({ label, ...rest }, ref) => ( <> <label htmlFor="field">{label}</label> <input id="field" ref={ref} {...rest} /> </> ), ) export default InputWithLabel
内容的提问来源于stack exchange,提问作者Andreas
相关产品推荐
相关产品推荐

