Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/424.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Typescript-键入一个函数,该函数接受数组,更改其属性之一,但仍返回相同类型的数组_Javascript_Typescript - Fatal编程技术网

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

Javascript Typescript-键入一个函数,该函数接受数组,更改其属性之一,但仍返回相同类型的数组,javascript,typescript,Javascript,Typescript,我将表单字段表示为对象,这些对象映射到类型上并基于返回的元素: 从“~types”导入{FieldProps}; 常量字段:FieldProps[]=[ {键入:“文本”,名称:“用户名”,值:,必需:true,…其他道具}, {键入:“密码”,名称:“密码”,值:,必需:true,…其他道具}, 等 ] 导出默认字段; 我遇到的问题是,我试图在提交表单后验证字段,并检查value中是否存在任何错误: handleSubmit=(e:FormEvent)=>{ e、 预防默认值(); cons

我将表单字段表示为对象,这些对象映射到
类型上并基于
返回的元素:

从“~types”导入{FieldProps};
常量字段:FieldProps[]=[
{键入:“文本”,名称:“用户名”,值:,必需:true,…其他道具},
{键入:“密码”,名称:“密码”,值:,必需:true,…其他道具},
等
]
导出默认字段;
我遇到的问题是,我试图在提交表单后验证字段,并检查
value
中是否存在任何错误:

handleSubmit=(e:FormEvent)=>{
e、 预防默认值();
const{validatedFields,errors}=fieldValidator(this.state.fields);
如果(错误){
this.setState({errors});
返回;
}
等
}
但此可重用验证函数有一个ts错误:

从“lodash.isEmpty”导入isEmpty;
/**
*用于验证表单字段的帮助器函数。
*
*@函数
*@param{array}fields-包含表单字段的数组。
*@返回{object}已验证/更新的字段和错误数。
*@throws{error}
*/
常量字段验证器=<
T扩展数组
>(
字段:T,
):{validatedFields:T;错误:number}=>{
试一试{
if(isEmpty(fields))抛出新错误(“必须提供表单字段数组以进行验证!”);
让errorCount:number=0;
//这会将“validatedFields”数组转换为{errors:string;type:string;name:
//字符串;值:字符串;必需?:boolean | undefined;}[]类型,当需要为“T”时,
//但“T”不会被推断为具有对象属性的数组:类型、值、必需、定义在其中的值
const validatedFields=fields.map(field=>{
让错误=”;
常量{type,value,required}=字段;
if((!value&&required)| |(isEmpty(value)&&required)){
errors=“必需。”;
}否则如果(
类型==“电子邮件”&&
!/^[A-Z0-9.\%+-]+@[A-Z0-9.-]+\[A-Z]{2,4}$/i.test(field.value)
) {
errors=“无效电子邮件。”;
}
如果(错误)errorCount+=1;
返回{…字段,错误};
});
返回{validatedFields,errors:errorCount};//TS error here
}捕捉(错误){
抛出字符串(错误);
}
};
导出默认字段验证器;
由于
validatedFields
变成:

{
    errors: string;
    name: string;
    value: string;
    type: string;
    required: boolean;
}[]
它返回
{validatedFields,errors}
,它抛出以下TS错误:

Type '{ errors: string; type: string; value: string; required?: boolean | undefined; }[]' is not assignable to type 'T'.
  '{ errors: string; type: string; value: string; required?: boolean | undefined; }[]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ type: string; value: string; required?: boolean | undefined; }[]'.ts(2322)
index.ts(17, 6): The expected type comes from property 'validatedFields' which is declared here on type '{ validatedFields: T; errors: number; }'
是否有一种方法可以将
T
推断为一个对象数组,该数组至少需要4个(或更多)属性,但返回相同类型的数组(仅使用更新的
errors
属性)


这就是您要搜索的内容吗

type EssentialField = { type: string; value: string; required?: boolean }[];
Typescript使用duck类型

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);
这是将类型与关联数组(
{[key:string]:any})
相交。通常像
associationarray['someKey']
那样访问,但也可以像
associationarray.someKey
那样使用它


好处是您的IDE应该在自动完成中向您建议
类型
必需
字段。

我通过将
T
扩展到
any[]
,然后将
验证字段的结果定义为T
来保存传入的类型,从而解决了这个问题:

const fieldValidator=<
T扩展任何[]
>(
字段:T,
):{validatedFields:T;错误:number}=>{
试一试{
如果(!fields | | fields.length<0)抛出新错误(“必须提供字段数组!”);
让errorCount:number=0;
const validatedFields=fields.map(field=>{
让错误=”;
常量{type,value,required}:Pick=field;
如果((!value&&required)| |((value&&value.length<0)&&required)){
errors=“必需。”;
}否则如果(
类型==“电子邮件”&&
!/^[A-Z0-9.\%+-]+@[A-Z0-9.-]+\[A-Z]{2,4}$/i.测试(值)
) {
errors=“无效电子邮件。”;
} 
如果(错误)errorCount+=1;
返回{…字段,错误};
})as-T;
返回{validatedFields,errors:errorCount};
}捕捉(错误){
抛出字符串(错误);
}
};

很接近,但上述两种解决方案都没有保留位于
FieldProps[]
中的其他类型。例如,
validatedFields[0]。验证后自动完成中既没有键入也没有提供标签
(这是必需的,请参见Typescript)。
type EssentialField = ({ type: string; value: string; required?: boolean }&{[key: string]: any})[];

// this allow you to do:
validatedFields[0].placeholder; // ...
// or
validatedFields[0].someUnknowProperty; // ...