React TypeScript表单验证报错:类型'(value?: string)=>...'无法赋值给ValidatorType
解决React + TypeScript表单验证类型不兼容问题
错误信息
Type '(value?: string) => "Required" | undefined' is not assignable to type 'ValidatorType'.
Types of parameters 'value' and 'value' are incompatible.
Type 'ValueType | undefined' is not assignable to type 'string | undefined'.
Type 'number' is not assignable to type 'string'.
问题代码
input.tsx
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> { error?: string; } const Input = ({ error, ...rest }: InputProps) => ( <div> <input {...rest} /> {error && <div>{error}</div>} </div> ); export default Input;
PasswordInput.tsx
import withValidation from "./WithValidation"; import Input from "./input"; const requiredValidator = (value?: string) => !value ? "Required" : undefined; const minLengthValidator = (value?: string) => value && value.length < 8 ? "Too short" : undefined; const difficultyValidator = (value?: string) => value && !/^(?=.*\d)(?=.*[A-Za-z]).*$/.test(value) ? "Must contain at least one number and letter" : undefined; const PasswordInput = withValidation(Input, [ requiredValidator, //报错行 minLengthValidator, //报错行 difficultyValidator //报错行 ]); export default PasswordInput;
withValidation.tsx
import * as React from "react"; type ValueType = string | number | string[]; type ValidatorType = (value?: ValueType) => string | undefined; interface RequiredInputProps { onChange?: React.ChangeEventHandler<HTMLInputElement>; onBlur?: React.FocusEventHandler<HTMLInputElement>; error?: string; value?: ValueType; } interface ValidatedInputState { finalized: boolean; } function withValidation<InputProps extends RequiredInputProps>( InputComponent: React.ComponentType<InputProps>, validators: ValidatorType[] = [] ) { return class InputWithValidation extends React.Component< InputProps, ValidatedInputState > { state: ValidatedInputState = { finalized: false }; handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.setState({ finalized: false }); if (this.props.onChange) { this.props.onChange(e); } }; handleBlur = (e: React.FocusEvent<HTMLInputElement>) => { this.setState({ finalized: true }); if (this.props.onBlur) { this.props.onBlur(e); } }; render() { const { error, value } = this.props; const firstInvalidValidator = validators.find( validate => !!validate(value) ); const validationError = this.state.finalized && firstInvalidValidator ? firstInvalidValidator(value) : undefined; return ( <InputComponent {...this.props} onChange={this.handleChange} onBlur={this.handleBlur} error={error || validationError} /> ); } }; } export default withValidation;
解决方案
核心问题是ValidatorType定义的参数包含number、string[]类型,但你的验证器仅接受string类型,导致类型不兼容。通过泛型让withValidation适配具体的value类型即可解决:
1. 修改withValidation的类型定义
将类型改为泛型,绑定验证器参数和输入组件的value类型:
import * as React from "react"; // 泛型验证器类型 type ValidatorType<T> = (value?: T) => string | undefined; interface RequiredInputProps<T> { onChange?: React.ChangeEventHandler<HTMLInputElement>; onBlur?: React.FocusEventHandler<HTMLInputElement>; error?: string; value?: T; } interface ValidatedInputState { finalized: boolean; } // 增加泛型参数T,指定value的类型 function withValidation<T, InputProps extends RequiredInputProps<T>>( InputComponent: React.ComponentType<InputProps>, validators: ValidatorType<T>[] = [] ) { return class InputWithValidation extends React.Component< InputProps, ValidatedInputState > { state: ValidatedInputState = { finalized: false }; handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.setState({ finalized: false }); if (this.props.onChange) { this.props.onChange(e); } }; handleBlur = (e: React.FocusEvent<HTMLInputElement>) => { this.setState({ finalized: true }); if (this.props.onBlur) { this.props.onBlur(e); } }; render() { const { error, value } = this.props; const firstInvalidValidator = validators.find( validate => !!validate(value) ); const validationError = this.state.finalized && firstInvalidValidator ? firstInvalidValidator(value) : undefined; return ( <InputComponent {...this.props} onChange={this.handleChange} onBlur={this.handleBlur} error={error || validationError} /> ); } }; } export default withValidation;
2. 调整PasswordInput的调用
明确指定泛型参数为string(或让TypeScript自动推断):
import withValidation from "./WithValidation"; import Input from "./input"; const requiredValidator = (value?: string) => !value ? "Required" : undefined; const minLengthValidator = (value?: string) => value && value.length < 8 ? "Too short" : undefined; const difficultyValidator = (value?: string) => value && !/^(?=.*\d)(?=.*[A-Za-z]).*$/.test(value) ? "Must contain at least one number and letter" : undefined; // 指定泛型参数为string,让验证器类型匹配 const PasswordInput = withValidation<string>(Input, [ requiredValidator, minLengthValidator, difficultyValidator ]); export default PasswordInput;
修改后,验证器的参数类型与withValidation接收的value类型完全匹配,类型错误将消失。
内容的提问来源于stack exchange,提问作者Chizo
相关产品推荐
相关产品推荐

