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

我将表单字段表示为对象,这些对象被映射并基于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属性)?


守候你守候我
浏览 168回答 2
2回答

当年话下

我设法通过扩展T到然后定义保留传入类型any[]的结果来弄清楚:validatedFields as Tconst fieldValidator = <&nbsp; T extends any[]>(&nbsp; fields: T,): { validatedFields: T; errors: number } => {&nbsp; try {&nbsp; &nbsp; if (!fields || fields.length < 0) throw new Error("You must supply an array of fields!");&nbsp; &nbsp; let errorCount: number = 0;&nbsp; &nbsp; const validatedFields = fields.map(field => {&nbsp; &nbsp; &nbsp; let errors = "";&nbsp; &nbsp; &nbsp; const { type, value, required }: Pick<BaseFieldProps, "type" | "value" | "required"> = field;&nbsp; &nbsp; &nbsp; if ((!value && required) || ((value && value.length < 0) && required)) {&nbsp; &nbsp; &nbsp; &nbsp; errors = "Required.";&nbsp; &nbsp; &nbsp; } else if (&nbsp; &nbsp; &nbsp; &nbsp; type === "email" &&&nbsp; &nbsp; &nbsp; &nbsp; !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)&nbsp; &nbsp; &nbsp; ) {&nbsp; &nbsp; &nbsp; &nbsp; errors = "Invalid email.";&nbsp; &nbsp; &nbsp; }&nbsp;&nbsp; &nbsp; &nbsp; if (errors) errorCount += 1;&nbsp; &nbsp; &nbsp; return { ...field, errors };&nbsp; &nbsp; }) as T;&nbsp; &nbsp; return { validatedFields, errors: errorCount };&nbsp; } catch (err) {&nbsp; &nbsp; throw String(err);&nbsp; }};

DIEA

这是你要找的吗?type EssentialField = { type: string; value: string; required?: boolean }[];打字稿使用鸭子打字。type FieldProps = {&nbsp; className?: string,&nbsp; disabled?: boolean,&nbsp; errors?: string,&nbsp; placeholder?: string,&nbsp; label: string,&nbsp; // onChange?: (e: React.ChangeEvent<any>) => void;&nbsp; name: string,&nbsp; type: string,&nbsp; readOnly?: boolean,&nbsp; required: boolean,&nbsp; value: string&nbsp; styles?: object};const fields: FieldProps[] = [&nbsp; {&nbsp;&nbsp; &nbsp; type: "text",&nbsp;&nbsp; &nbsp; label: "Username",&nbsp;&nbsp; &nbsp; name: "username",&nbsp;&nbsp; &nbsp; errors: "",&nbsp; &nbsp; value: "",&nbsp;&nbsp; &nbsp; required: true,&nbsp; },&nbsp; {&nbsp;&nbsp; &nbsp; className: "example",&nbsp; &nbsp; type: "password",&nbsp;&nbsp; &nbsp; label:"Passowrd",&nbsp;&nbsp; &nbsp; name: "password",&nbsp;&nbsp; &nbsp; errors: "",&nbsp;&nbsp; &nbsp; value: "",&nbsp;&nbsp; &nbsp; required: true,&nbsp;&nbsp; &nbsp; styles: { width: "150px" },&nbsp; }];type EssentialField = { type: string; value: string; required?: boolean }[];const fieldValidator = (&nbsp; fields: EssentialField,): { validatedFields: EssentialField; errors: number } => {&nbsp; try {&nbsp; &nbsp; if (!fields || fields.length < 0) throw new Error("You must supply an array of fields!");&nbsp; &nbsp; let errorCount: number = 0;&nbsp; &nbsp; const validatedFields = fields.map(field => {&nbsp; &nbsp; &nbsp; let errors = "";&nbsp; &nbsp; &nbsp; const { type, value, required } = field;&nbsp; &nbsp; &nbsp; if ((!value && required) || ((value && value.length < 0) && required)) {&nbsp; &nbsp; &nbsp; &nbsp; errors = "Required.";&nbsp; &nbsp; &nbsp; } else if (&nbsp; &nbsp; &nbsp; &nbsp; type === "email" &&&nbsp; &nbsp; &nbsp; &nbsp; !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(field.value)&nbsp; &nbsp; &nbsp; ) {&nbsp; &nbsp; &nbsp; &nbsp; errors = "Invalid email.";&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; if (errors) errorCount += 1;&nbsp; &nbsp; &nbsp; return { ...field, errors };&nbsp; &nbsp; });&nbsp; &nbsp; return { validatedFields, errors: errorCount };&nbsp; } catch (err) {&nbsp; &nbsp; throw String(err);&nbsp; }};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; // ...// orvalidatedFields[0].someUnknowProperty; // ...这是将类型与关联数组 ( {[key: string]: any})) 相交。通常这样访问associativeArray['someKey'],但也可以这样使用associativeArray.someKey。好处是您的 IDE 应该在自动完成中为您推荐type和字段。required
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript