React TS中为TextField新增inputMode属性报类型错误如何解决
问题原因
报错本质是TypeScript的类型校验逻辑导致的:
- 你仅在
INumberFieldProps中声明了inputMode属性,但TextField组件的props类型ITextFieldProps中没有定义该字段 - TypeScript校验组件传参时,只会对照组件自身声明的props类型做检查,不会因为组件内部用了
...rest透传属性,就允许传入未在类型中声明的属性,哪怕这个属性最终会传给原生DOM也不会自动放行 - 另外你的代码还有两个隐藏的类型问题:给
React.forwardRef外层错误包裹了React.FunctionComponent,会导致ref类型声明失效;传入的value属性也未在ITextFieldProps中声明,后续同样会触发类型报错。
修复方案
方案1(推荐,通用组件最佳实践)
让组件props类型直接继承原生DOM的属性类型,不需要重复声明原生已经支持的属性,同时修正forwardRef的错误写法:
修正后的TextField.tsx
import React, { useState } from "react"; // 继承原生input的所有属性,用Omit排除掉我们要自定义类型的字段 export interface ITextFieldProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'onChange'> { type?: "text" | "search"; onChange?: (value: string) => void; required?: boolean; } // 不要给forwardRef外层包裹React.FunctionComponent,直接赋值即可保留正确的类型推导 export const TextField = React.forwardRef< HTMLInputElement, ITextFieldProps >((props, ref) => { const { type = "text", onChange, required = true, ...rest } = props; const [value, setValue] = useState(""); function handleChange(e: React.FormEvent<HTMLInputElement>) { setValue(e.currentTarget.value); onChange?.(e.currentTarget.value); } return ( <input ref={ref} type={type} value={value} onChange={handleChange} required={required} {...rest} /> ); });
修正后的NumberField.tsx
import React, { useState } from "react"; import { TextField } from "./TextField"; // 继承TextField的所有props类型,如果需要限制inputMode的可选值,可以重写对应字段 export interface INumberFieldProps extends React.ComponentProps<typeof TextField> { inputMode?: "numeric"; } export const NumberField = React.forwardRef< HTMLInputElement, INumberFieldProps >((props, ref) => { const { inputMode = "numeric", onChange } = props; const [value, setValue] = useState(""); function handleChange(value: string) { const updatedValue = value.replace(/\D/g, ""); setValue(updatedValue); onChange?.(updatedValue); } return ( <TextField ref={ref} inputMode={inputMode} onChange={handleChange} value={value} /> ); });
方案2(严格控制组件属性时使用)
如果你不希望TextField暴露所有原生input属性,只想单独支持需要的属性,直接在ITextFieldProps中手动补充缺失的字段声明即可:
export interface ITextFieldProps { type?: "text" | "search"; onChange?: (value: string) => void; required?: boolean; // 补充缺失的属性声明 inputMode?: React.InputHTMLAttributes<HTMLInputElement>['inputMode']; value?: string; }
这种写法可以严格限制外部能传入的属性范围,适合对组件API管控要求高的场景,但需要手动维护所有需要透传的属性类型,维护成本更高。
内容的提问来源于stack exchange,提问作者Judoboy Alex
相关产品推荐
相关产品推荐

