为了账号安全,请及时绑定邮箱和手机立即绑定

键入一个接受数组的函数,更改其属性之一,但仍返回相同类型的数组

键入一个接受数组的函数,更改其属性之一,但仍返回相同类型的数组

守候你守候我 2023-02-24 10:38:18
我将表单字段表示为对象,这些对象被映射并基于type返回的 React 元素:import { FieldProps } from "~types";const fields: FieldProps[] = [  { type: "text", name: "username", value: "", required: true, ...other props },  { type: "password", name: "password", value: "", required: true, ...other props },  ...etc]export default fields;我遇到的问题是我试图在提交表单后验证字段并检查是否有任何错误value: handleSubmit = (e: FormEvent<HTMLFormElement>) => {    e.preventDefault();    const { validatedFields, errors } = fieldValidator(this.state.fields);    if(errors) {      this.setState({ errors });      return;    }    ...etc }但是这个可重用的验证函数有一个 ts 错误:import isEmpty from "lodash.isempty";/** * Helper function to validate form fields. * * @function * @param {array} fields - an array containing form fields. * @returns {object} validated/updated fields and number of errors. * @throws {error} */const fieldValidator = < T extends Array<{ type: string; value: string; required?: boolean }>>(  fields: T,): { validatedFields: T; errors: number } => {  try {    if (isEmpty(fields)) throw new Error("You must supply an array of form fields to validate!");    let errorCount: number = 0;    // this turns the "validatedFields" array into an { errors: string; type: string; name:     // string; value: string; required?: boolean | undefined;}[] type, when it needs to be "T",     // but "T" won't be inferred as an Array with Object props: type, value, required, value defined within it    const validatedFields = fields.map(field => {      let errors = "";      const { type, value, required } = field;      if ((!value && required) || (isEmpty(value) && required)) {        errors = "Required.";      } else if (        type === "email" &&        !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(field.value)      ) {        errors = "Invalid email.";      }      if (errors) errorCount += 1;      return { ...field, errors };    });有没有一种方法可以推断T为至少需要 4 个(或更多)属性的对象数组,但返回相同类型的数组(仅具有更新的errors属性)?
查看完整描述

2 回答

?
当年话下

TA贡献1890条经验 获得超9个赞

我设法通过扩展T到然后定义保留传入类型any[]的结果来弄清楚:validatedFields as T


const fieldValidator = <

  T extends any[]

>(

  fields: T,

): { validatedFields: T; errors: number } => {

  try {

    if (!fields || fields.length < 0) throw new Error("You must supply an array of fields!");

    let errorCount: number = 0;


    const validatedFields = fields.map(field => {

      let errors = "";

      const { type, value, required }: Pick<BaseFieldProps, "type" | "value" | "required"> = field;

      if ((!value && required) || ((value && value.length < 0) && required)) {

        errors = "Required.";

      } else if (

        type === "email" &&

        !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)

      ) {

        errors = "Invalid email.";

      } 


      if (errors) errorCount += 1;


      return { ...field, errors };

    }) as T;


    return { validatedFields, errors: errorCount };

  } catch (err) {

    throw String(err);

  }

};


查看完整回答
反对 回复 2023-02-24
?
DIEA

TA贡献1820条经验 获得超2个赞

这是你要找的吗?


type EssentialField = { type: string; value: string; required?: boolean }[];

打字稿使用鸭子打字。


type FieldProps = {

  className?: string,

  disabled?: boolean,

  errors?: string,

  placeholder?: string,

  label: string,

  // onChange?: (e: React.ChangeEvent<any>) => void;

  name: string,

  type: string,

  readOnly?: boolean,

  required: boolean,

  value: string

  styles?: object

};



const fields: FieldProps[] = [

  { 

    type: "text", 

    label: "Username", 

    name: "username", 

    errors: "",

    value: "", 

    required: true,

  },

  { 

    className: "example",

    type: "password", 

    label:"Passowrd", 

    name: "password", 

    errors: "", 

    value: "", 

    required: true, 

    styles: { width: "150px" },

  }

];


type EssentialField = { type: string; value: string; required?: boolean }[];


const fieldValidator = (

  fields: EssentialField,

): { validatedFields: EssentialField; errors: number } => {

  try {

    if (!fields || fields.length < 0) throw new Error("You must supply an array of fields!");

    let errorCount: number = 0;


    const validatedFields = fields.map(field => {

      let errors = "";

      const { type, value, required } = field;

      if ((!value && required) || ((value && value.length < 0) && required)) {

        errors = "Required.";

      } else if (

        type === "email" &&

        !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(field.value)

      ) {

        errors = "Invalid email.";

      }


      if (errors) errorCount += 1;


      return { ...field, errors };

    });


    return { validatedFields, errors: errorCount };

  } catch (err) {

    throw String(err);

  }

};


const { validatedFields, errors } = fieldValidator(fields)

console.log(validatedFields)

console.log(errors);

这消除了错误,没有使用as any或其他技巧。


编辑:也许你想要这样的东西:


type EssentialField = ({ type: string; value: string; required?: boolean }&{[key: string]: any})[];


// this allow you to do:

validatedFields[0].placeholder; // ...

// or

validatedFields[0].someUnknowProperty; // ...

这是将类型与关联数组 ( {[key: string]: any})) 相交。通常这样访问associativeArray['someKey'],但也可以这样使用associativeArray.someKey。


好处是您的 IDE 应该在自动完成中为您推荐type和字段。required


查看完整回答
反对 回复 2023-02-24
  • 2 回答
  • 0 关注
  • 130 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信