reactjs - 模型通用 Typescript 类型以强制多个道具具有相同的键集
问题描述
我正在尝试创建这个通用<FormBuilder />
组件。我不想拿两套不同的道具,defaultValues
和fields
。使用泛型,我不想强制两个道具使用完全相同的键。
到目前为止,这是我想出的(这也可能有助于解释我想要实现的目标):
一个<FormBuilder />
可以生成表单的组件,带有这样的 API。
<FormBuilder
initialValues={{
firstName: undefined,
lastName: undefined,
}}
fields={{
firstName: { type: 'text', label: 'First Name', required: true },
lastName: { type: 'text', label: 'Last Name', required: true },
}}
onSubmit={value => {
// Value is strongly typed, with keys 'firstName' and 'lastName'
}}
/>
这很好,并且给了我强大的类型检查。如果我从其中一个道具中删除或添加一件事,Typescript 会给我一个警告。这将确保我在进行某些更改时永远不会忘记更新其他道具。此外,onSubmit()
回调还将具有包含所使用的确切键的强类型。
从“外部”来看,这个组件效果很好。 问题在于这是使用Record<>
类型的事实,我无法在保持强类型的同时对其进行迭代。
下面你可以看到我对这个组件的实现。如您所见,我必须创建自己的iterator()
函数来以更好的方式迭代数据,而且我还必须对一些值进行类型转换。
type FormProps<T, K extends keyof T> = {
fields: Record<K, FieldItem>;
initialValues: Record<K, string | undefined>;
onSubmit: (value: Record<K, string | undefined>) => void;
};
export function FormBuilder<T, K extends keyof T>(props: FormProps<T, K>) {
const [fields, setFields] = useState<Record<K, string | undefined>>(props.initialValues);
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
props.onSubmit(fields);
}
function handleChange(value: FieldOutput) {
setFields({ ...fields, [value.name]: value.value });
}
return (
<form onSubmit={handleSubmit}>
{iterator(fields).map(({ value, key }) => (
<React.Fragment key={key as string}>
<FieldFactory valueKey={key as string} value={value} field={props.fields[key]} onChange={handleChange} />
</React.Fragment>
))}
</form>
);
}
当我需要遍历onSubmit()
处理程序中的值时,该组件的“外部”也会出现同样的问题。
迭代器实现如下。
export function iterator<Item>(item: Item) {
const result: Array<{ key: keyof typeof item; value: Item[keyof typeof item] }> = [];
let k: keyof Item;
for (k in item) {
const value = item[k];
result.push({ value, key: k });
}
return result;
}
我在寻找什么
我愿意接受各种建议。一种在仍然保持类型的同时迭代对象的方法(从我从其他 SO 帖子中可以看到,这似乎很困难/不可能),或者可能是另一种类型/结构化数据的方法,并且仍然达到相同的效果。
我试过使用Array
,Set
但没有任何运气。
解决方案
推荐阅读
- javascript - javascript:按空格分割字符串并使用地图和过滤器制作列表
- java - java.lang.ArrayIndexOutOfBoundsException:使用并行流将元素添加到列表时
- regex - 正则表达式:以数字/星号或“+”号开头,最少包含 2 位数字,以数字/星号结尾
- java - 如何在堆栈问题中使用字符数组(或字节数组)逐行读取
- node.js - node.js 中的 require('dotenv').config()
- java - JUnit & Mockito - thenReturn 在 WebServiceTemplate 上使用时返回 null
- haskell - 如何获取 Haskell 中字符串列表的跨度索引?
- coq - coqc: -Q.PLF: 没有这样的文件或目录
- java - 当 json 中的一个键包含值列表时,使用 Retrofit 将 JSON 键值对转换为 Java 对象
- php - 查询时间戳列早于 X 小时的数据库行