0

我发现了这个使用单个更改函数来处理 React 和 Typescript 的多个文本输入和状态更改的聪明示例。该示例自然使用普通字符串类型:


type MyEntity = {
   name: string;
  // would work with any other fields
}

const handleChange = (fieldName: keyof MyEntity) => (
    e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
  ) => {
    setValues({ ...values, [fieldName]: e.currentTarget.value });

但是,我的字符串类型是字典。例如:

{[index: string]: string}

...其中索引是语言代码字符串,其对应的值是该语言内容的字符串。例如,名称对象看起来像,name:{'en': 'Michael', 'es': 'Miguel'}

这是我当前希望为所有文本字段工作的特定于字段的更改处理程序。注意- selectedLanguage是一个字符串状态变量,带有用户选择的语言代码,为简洁起见省略。请参阅下面的代码框链接以获取完整版本):


type StringLanguage = {
  [index: string] : string;
}

interface MyEntity {
  name: StringLanguage;
}

const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setData((prevData) => {
      return {
        ...prevData,
        name: {
          ...prevData.name,
          [selectedLanguage]: e.target.value
        }
      };
    });
  };

这是我尝试使用与我找到的示例类似的方法。

  const handleChange2 = (fieldName: keyof MyEntity) => (
    e: React.ChangeEvent<HTMLInputElement>
  ) => {
    
    setData((prevData) => { 
      return {
      ...prevData, 
      [fieldName]: {
        ...prevData[fieldName],
        [selectedLanguage]: e.currentTarget.value 
        }
      };
    });
  };

TS 在代码行上给了我错误,“ Spread types may only be created from object types.ts(2968) ”: ...prevData[fieldName]

但是 prevData 是一个对象,并且在特定于字段的版本中它可以工作。如何让这个更通用的函数与我的字典类型 StringLanguage 一起使用?:

这是文本输入的用法:

onChange={(e) => handleChange2("name")}

最后,这是一个包含我正在做的完整示例的代码框。随意注释掉代码进行实验。我已将有效的版本保持为活动状态,并从上面注释掉了无效的内容:

例子

4

1 回答 1

1

嘿,问题是您的界面MyEntity中有一个id: string属性,这就是 ts 编译器抱怨的原因。

如果你想做一些通用的事情,它会是这样的

  const isPrimitive = (yourVariable: any) =>
    typeof yourVariable === "object" && yourVariable != null;

  const overrideObject = (original: object, override: object) => ({
    ...original,
    ...override
  });

  const handleChange = (fieldName: keyof MyEntity) => (
    e: React.ChangeEvent<HTMLInputElement>
  ) => {
    setData((prevData: MyEntity) => {
      return {
        ...prevData,
        [fieldName]: isPrimitive(prevData[fieldName])
          ? e.currentTarget.value
          : overrideObject(prevData[fieldName] as object, {
              [selectedLanguage]: e.currentTarget.value
            })
      };
    });
  };
于 2021-10-07T18:35:35.513 回答