Я пытаюсь принять два поля [{fileName: string, file: File}]
в динамической форме Typescript на основе React, где пользователь может добавить несколько наборов полей [{fileName: string, file: File}]
при успешной проверке ZOD. Ниже приведены коды:
Тип:
interface MultipleFileType {
info: [{
fileName: string;
file: File
}]
}
Схема проверки
const multipleSchema = z.object({
fileName: z.string({ required_error: "Name is required" }).min(5, { message: "Minimum length is 5" }),
file: z
.any()
.refine((files) => files?.length == 1, 'Image is required.')
.refine((files) => files?.[0]?.size <= (1024 * 1024 * 2.5), `Max file size is 2.5 MB.`)
.refine(
(files) => ['image/jpeg', 'image/jpg', 'image/png'].includes(files?.[0]?.type),
'.jpg, .jpeg, .png and .webp files are accepted.',
),
})
export const multipleFileUploaderSchema = z.object({
info: z.array(
multipleSchema
)
})
Форма:
<Form {...form}>
<form onSubmit = {form.handleSubmit(onSubmit)} className = "space-y-6">
{fields.map((item, index) => (
<div key = {item.id}>
<div className = "md:flex md:flex-col">
<FormField
key = {index}
control = {form.control}
name = {`info.${index}.fileName`} <------- ERROR 1
render = {({ field }) => (
<FormItem>
<FormLabel>Filename</FormLabel>
<FormControl>
<Input type = "text" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<div className = "md:flex md:flex-col">
<FormField
key = {index}
control = {form.control}
name = {`info.${index}.file`} <------- ERROR 2
render = {({ field: { onChange, ...fieldProps } }) => (
<FormItem>
<FormLabel>Picture</FormLabel>
<FormControl>
<input
type = "file"
{...fieldProps}
value = {""}
onChange = {(event) => {
const { files } = getImageData(event, index);
// setPreviewUrl(displayUrl);
onChange(files);
}}
ref = {imgInputRef}
hidden
/>
</FormControl>
{/* <FormMessage /> */}
</FormItem>
)}
/>
</div>
<Button
disabled = {fields.length === 1}
className = "text-red-500"
variant = "outline"
size = "icon"
type = "button"
onClick = {() => remove(index)}
>
<Trash className = "h-4 w-4" />
</Button>
<Button
disabled = {fields.length > 2.5 * 1024 * 1024 || !form.formState.isValid}
className = "ml-4"
variant = "outline"
size = "icon"
type = "button"
onClick = {() =>
append({
fileName: "",
file: new File([], "/vite.svg"),
})
}
>
<Plus className = "h-4 w-4" />
</Button>
</div>
))}
<Button type = "submit" className = "ml-4">
Submit
</Button>
</form>
</Form>;
Ошибка, возникшая в обеих маркировках ERROR 1 и ERROR 2, выглядит следующим образом:
Type '
info.${number}.fileName' is not assignable to type '"info" | "info.0" | "info.0.fileName" | "info.0.file"'.ts(2322) controller.d.ts(20, 5): The expected type comes from property 'name' which is declared here on type 'IntrinsicAttributes & { render: ({ field, fieldState, formState, }: { field: ControllerRenderProps<MultipleFileType, "info" | "info.0" | "info.0.fileName" | "info.0.file">; fieldState: ControllerFieldState; formState: UseFormStateReturn<...>; }) => ReactElement<...>; } & UseControllerProps<...>'
Любые предложения помогут.
Вы всегда можете преобразовать эти свойства имени в тип Path<z.infer<typeof yourSchemaHere>>
, где Path
экспортируется из формы реагирования, хотя способ структурирования ваших типов вы сообщаете машинописному сценарию, что длина массива всегда будет равна 1, и с кодом которым вы поделились, трудно сказать, тот ли это индекс, который вы сопоставляете. Если вы не хотите, чтобы длина этого массива всегда была равна 1, измените это:
interface MultipleFileType {
info: [{
fileName: string;
file: File
}]
}
export const multipleFileUploaderSchema = z.object({
info: z.array(
multipleSchema
)
})
к этому:
interface MultipleFileType {
info: {
fileName: string;
file: File
}[]
}
export const multipleFileUploaderSchema = z.object({
info: multipleSchema.array()
})
Это сработало!!! Это было несоответствие типа объявления массива.