. It works well," /> . It works well," /> . It works well,"/>

How to create a type for file type `Record<string, File>` in zod

19.7k Views Asked by At

I use input type="file" and instead of saving data in FileData I use just plain object and created a type for it: Record<string, File>. It works well, but when I try to create a validator with zod – I don't get how to create the same type for it.

The usage:

import { object as zodObject, string, number } from 'zod';
import { useValidators } from '../some';

const useValidation = () => {
  const { createResolver } = useValidators();
  
  return {
    resolver: createResolver(
      zodObject({
        name: string(),
        price: number(),
        files: ???,  
      })
    ),
  };
}; 

The doc is quite excessive, but I could not find any example for my case: https://github.com/colinhacks/zod

The usage of input:


const App = () => {
  const [files, setFiles] = useState<Record<string, File>>({}); 

  return (
    <input 
      type="file" 
      onChange={event => {
        const files = event.target.files;
        const newFiles: Record<string, File> = {};
        const keys = Object.keys(files);
        
        for(let i = 0; i < keys.length; i++) {
          const file = newFiles[key];
          newFiles[file.name] = file;
        }

        setFiles(newFiles);
      }}
    />

  )

}

5

There are 5 best solutions below

0
Samat Zhetibaev On

My colleague has found the solution:

// useValidation file
import { object as zodObject, string, number, record, any } from 'zod';
import { useValidators } from '../some';

const useValidation = () => {
  const { createResolver } = useValidators();
  
  return {
    resolver: createResolver(
      zodObject({
        name: string(),
        price: number(),
        files: record(any()).nullable(),  
      })
    ),
  };
};  

And in the file that uses object with file data we use it in this way:

// fileInput on `onRemove` action return `fileName: string` and my file object looks like this:  { fileName: File } 

const [files, setFiles] = useState<Record<string, File> | null>(null);

<FileInput 
  onChange={(fileName) => {
    const updatedFiles = { ...files as Record<string, File> }; 
    delete updatedFiles[fileName];
    setFiles(updatedFiles);
  }}
/>
0
Deiminas On

zodSchema:

  file:
    typeof window === "undefined"
      ? z.string()
      : record(any()).nullable(),

initialValues:

file: "undefined",
3
Rin On

Maybe z.instanceof can solve it?

If you want to validate the File type ...

z.instanceof (File)

Or, for FileList type...

z.instanceof (FileList)


https://github.com/colinhacks/zod/issues/387

0
abdelrahman aboneda On

try this:

    z.object({
        file: z
         .any()
         .refine((files) => files?.length == 1, "File is required.")  
    })

and then use other file properties in refine to filter it as u need like:

  • files?.[0]?.size
  • files?.[0]?.type
1
erickcrick On
  requestFiles: z
.array(
  z
    .instanceof(File)
    .refine((file) => file.size < 2 * 1024 * 1024, 'File size must be less than 2MB'),
)
.min(1, 'At least 1 file is required')
.refine(
  (files) => files.every((file) => file.size < 2 * 1024 * 1024),
  'File size must be less than 2MB',
),
        <FormField
          name="requestFiles"
          control={form.control}
          render={({ field }) => (
            <FormItem className="md:col-span-4 col-span-1">
              <FormLabel>Attach Files</FormLabel>
              <FormControl>
                <Input
                  type="file"
                  className=" border-slate-300"
                  onChange={(e) => {
                    // Convert the FileList to an array and update the form state
                    const filesArray = Array.from(e.target.files || []);
                    field.onChange(filesArray);
                  }}
                  multiple // Allow multiple file selection
                />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />