我有一个表单的基本接口,但我的每个页面都扩展了该接口以创建扩展表单。现在我想创建一个子组件,它根据扩展模板生成表单。
// childComponent.tsx
export default function ProductSourceFormTemplate<T extends IProductSourceBase>({ formSchema }: {
formSchema: z.ZodType<T>,
}) {
type FormValues = z.infer<typeof formSchema>
const defaultValues: T = useMemo<T>(() => ({
sourceId: ""
}) as T, [searchParams])
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: defaultValues,
});
// render form
}
但是它在defaultValues上给出了这个错误
Type 'T' is not assignable to type 'AsyncDefaultValues<T> | DefaultValues<T> | undefined'.
Type 'IProductSourceBase' is not assignable to type 'AsyncDefaultValues<T> | DefaultValues<T> | undefined'.
Type 'IProductSourceBase' is not assignable to type 'DefaultValues<T>'.ts(2322)
而且当我想创建表单元素时,没有一个名称被识别。
我想要的是让我的父组件创建
productBaseSchema.extend({})
,这是一个 z.ZodObject<{}>
,然后将此扩展模式传递给子 const extendedSchema: z.ZodObject<z.objectUtil.extendShape<{}>
,子组件还可以在其 props 中提供 onSubmit、渲染函数,因此只有父组件只处理额外的事情领域。
示例:
export interface IProductSourceBase {
productId: string;
sourceId: number;
sourceMeta?: any;
}
const productSourceBaseSchema = z.object({
productId: z.string().nonempty(translate("Product ID is required")),
sourceId: z.coerce.number().int(translate("Source ID must be an integer")).gt(0, translate("A source must be selected")),
});
const extendedSchema = productSourceBaseSchema.extend({
sourceMeta: z.object({
sourceUrl: z.string().url(translate("This is not a valid URL")).nonempty(translate("Url is required")).refine(
(url) => /\/spreadsheets\/d\/([a-zA-Z0-9-_]{16,44})/.test(url), // Test for valid Spreadsheet ID
{
message: translate("This is not a valid Google Spreadsheet ID"), // Custom error message
}
),
cell: z.string().nonempty(translate("Cell number is required")).refine(
(cell) => /^[A-Za-z]+[1-9]\d*$/.test(cell), // Check if the cell matches the pattern
{
message: translate("Invalid cell reference format"), // Custom error message for invalid format
}
),
}),
});
在这里,我确保您使用
FormValues
作为 defaultValues
和 useForm
的分配,同时还使用 react-hook-form
的泛型 DefaultValues
——这将深度部分应用于给定类型(只是为了清理)。而且,对于这样的表单,如果您将 transform
或 default
合并到您的 zod
模式中,使用 z.input
而不是 z.infer
可以让事情变得更容易一些,但并不直接应用在这里。
import { DefaultValues, ... } from "react-hook-form"
...
type FormValues = z.infer<typeof formSchema>
const defaultValues = useMemo<DefaultValues<FormValues>>(() => ({
sourceId: ""
}), [])
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues,
});
...