手写 Schema 会存在哪些挑战
手写 Schema 的同学应该会遇到一个痛点,x-component-props 没办法根据 x-component 来自行推断。我们先看看 formily 2.x 源代码中是如何定义 ISchema。简化以后如下:
type ISchema< Component = any,ComponentProps = any> = {
['x-component']?: Component
['x-component-props']?: ComponentProps
}
因为同一个 ISchema 中会使用多种 Component ,使用方式如下:
const FormSchema: ISchema<'Input' | 'Select', InputProps | SelectProps> = {
type: 'object',
'x-component': 'Input',
'x-component-props': {
...
},
};
问题就在于 'x-component-props' 的类型为 InputProps | SelectProps,ts 补全和校验无法根据 'x-component': 'Input' 收敛至 InputProps。
如何通过 x-component 收敛 x-component-props 的类型
formily 2.x 导出的 ISchema 因为要考虑通用性,所以给出的泛型参数是比较宽泛的,我们如何基于现有的逻辑来扩展出更有效的收敛逻辑,先考虑最基础的类型收敛方式:
interface IInputProps {
placeholder?: string
}
interface ISelectProps {
options?: {
label: string,
value: string
}[]
}
interface ComponentPropsMap {
Input: IInputProps;
Select: ISelectProps;
}
type ComponentNameKey = keyof ComponentPropsMap;
interface ISchema<T extends ComponentNameKey> {
'x-component': T,
'x-component-props': ComponentPropsMap[T]
}
// type MapISchema = ISchema<"Input"> | ISchema<"Select">
type MapISchema<T extends ComponentNameKey = ComponentNameKey> = T extends any ? ISchema<T> : never;
const schema: MapISchema = {
'x-component': 'Select',
'x-component-props': {
options:[]
}
}
const schema2: MapISchema = {
'x-component': 'Input',
'x-component-props': {
placeholder: 'placeholder'
}
}
使用 ComponentPropsMap 我们建立了类型间的关联关系,实现了通过 x-component 的值来推断出 x-component-props 应该有的类型。
在线示例可以参考 ts playground
formily ISchema 的定义本质上是一个类型的迭代,仅需要在以上代码中简单扩展即可,暂不赘述。
注意我们将对应关系提取至最外层的 ComponentPropsMap。避免在迭代中传递。
下篇预告
以上我们有了常量 schema ,我们是否能够根据该常量推断出 form 值的类型格式呢?敬请期待。