You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 11:43:28