我创建了一个表单生成器,它接受配置并呈现表单。基本结构如下所示:
const sampleConfig = {
meta: 'someMetaData',
fields: [
{
controlName: 'a',
type: 'text'
},
{
controlName: 'b',
type: 'select'
},
{
controlName: 'c',
type: 'subGroup',
fields: [
{
controlName: 'cA',
type: 'number'
}
]
}
]
}
此配置将创建 3 个表单字段:一个文本字段、一个选择字段和一个带有数字字段的子组。您可以看到每个字段可以是一个控件,也可以有一个带有自己的字段数组的子组。
我已经强输入了配置,对于这个例子,我们假设它是这样的:
interface Field {
controlName: string;
type: 'number' | 'select' | 'text' | 'subGroup'
fields?: Field[]
}
interface FormConfig {
meta: string
fields: Field[]
}
但我想启用一个泛型来验证controlName对应模型的 s 。
对于此示例,模型将如下所示:
interface SampleModel {
a: string;
b: string;
c: {
cA: number;
}
}
理想情况下,我可以像这样键入配置:
const sampleConfig: FormConfig<SampleModel> = { ... }
如果我的控件名称与键不对齐,它是否会引发编译错误。我可以很容易地确保 controlName 与模型键之一匹配,如下所示:
interface Field<M, K extends keyof M> {
name: K;
type: 'select' | 'text' | 'number'
}
interface SubGroupField<M, K extends keyof M> extends Omit<Field<M, K>, 'type'> {
type: 'subGroup',
fields?: Field<M[K], keyof M[K]>[];
}
interface FormConfig<M, K extends keyof M> {
meta: 'string';
fields: Field<M, K>[] | SubGroupField<M[K], keyof M[K]>[];
}
虽然这不会将配置与模型紧密绑定,但它只是确保控件名称仅限于模型键名称,每个字段都可以使用相同的 controlName,只要它匹配其中一个,Typescript 就不会抱怨模型的关键名称。
fields如果我将属性设为对象而不是数组并使用controlNames 作为每个字段对象的键,这将很容易实现。不幸的是,这个库已经存在了一段时间,如果可能的话,我需要避免重大的重大变化。
显然,这可能对所有类型的场景都有用,因此,如果您对问题有更好的标题,我很乐意更改它以帮助其他人更轻松地找到它。我非常彻底地搜索了类似的问题,但找不到任何问题,所以如果已经回答了这个问题,我也会更新以指向那里。
对此的任何指导将不胜感激。谢谢!
已编辑:包括来自@Linda Paise 的建议,将“子组”隔离为拥有类型,强制只有这种类型才能具有字段属性。