子组件打字稿中 zod 的通用扩展类型

问题描述 投票:0回答:1

我有一个表单的基本接口,但我的每个页面都扩展了该接口以创建扩展表单。现在我想创建一个子组件,它根据扩展模板生成表单。

// 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
            }
        ),
    }),
});
typescript next.js react-hook-form zod
1个回答
0
投票

在这里,我确保您使用

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,
    });
...
© www.soinside.com 2019 - 2024. All rights reserved.