Closed JacobWeisenburger closed 1 year ago
The difference is that the inferred type with regex would be string
, whereas with custom it is a template literal
good point
I was still hoping for some other examples. Perhaps other people have some good ideas.
I use it for file validation.
Example for NestJS:
const fileSchema = z
.custom<Express.Multer.File[]>()
.refine((files) => files?.length === 1, 'single file is allowed')
.refine((files) => files?.[0]?.size <= 5 * 1024 * 1024, "file shouldn't be more than 5 MB")
.refine(
(files) => ['image/jpg', 'image/jpeg', 'image/png'].includes(files?.[0]?.mimetype),
'Accepted Formats: JPG/JPEG/PNG',
);
I'm not sure if this can be done in some other way. (i don't provide a validation function to custom because multer takes care of that).
Example for browser (NextJS):
const fileSchema = z
.custom<FileList>(files => files instanceof FileList)
.refine(
files => ['image/jpg', 'image/jpeg', 'image/png'].includes(files?.[0]?.type),
'Accepted Formats: JPG/JPEG/PNG'
)
.refine(files => files?.[0]?.size <= 1 * 1024 * 1024, "Size shouldn't be more than 1 MB")
Thanks, I like the thought. But this seems more like a showcase of refine
rather than a good use case for custom
.
const fileSchema = z .custom<FileList>(files => files instanceof FileList) .refine( files => ['image/jpg', 'image/jpeg', 'image/png'].includes(files?.[0]?.type), 'Accepted Formats: JPG/JPEG/PNG' ) .refine(files => files?.[0]?.size <= 1 * 1024 * 1024, "Size shouldn't be more than 1 MB")
have you thought about doing it this way:
const fileSchema = z
.instanceof( FileList )
.refine(
files => [ 'image/jpg', 'image/jpeg', 'image/png' ].includes( files?.[ 0 ]?.type ),
'Accepted Formats: JPG/JPEG/PNG'
)
.refine( files => files?.[ 0 ]?.size <= 1 * 1024 * 1024, "Size shouldn't be more than 1 MB" )
I wasn't aware of .instanceof, this seems more elegant. Thank you.
const fileSchema = z .custom<FileList>(files => files instanceof FileList) .refine( files => ['image/jpg', 'image/jpeg', 'image/png'].includes(files?.[0]?.type), 'Accepted Formats: JPG/JPEG/PNG' ) .refine(files => files?.[0]?.size <= 1 * 1024 * 1024, "Size shouldn't be more than 1 MB")
have you thought about doing it this way:
const fileSchema = z .instanceof( FileList ) .refine( files => [ 'image/jpg', 'image/jpeg', 'image/png' ].includes( files?.[ 0 ]?.type ), 'Accepted Formats: JPG/JPEG/PNG' ) .refine( files => files?.[ 0 ]?.size <= 1 * 1024 * 1024, "Size shouldn't be more than 1 MB" )
Now I remember why I do it like that, "FileList" is only available in browser so using instanceof would throw a reference error in a framework like nextjs but in nestjs, I will be using the way you recommended (instanceof).
We use it for validating IBAN or country code:
import { isValid } from 'iban';
import { z } from 'zod';
const iban = z.custom<string>((val) => {
return isValid(val as string);
});
type Account = z.infer<typeof iban>;
iban.parse('BE539007547034'); // 'BE539007547034'
iban.parse('123456789123456789'); // throws;
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I have a zod validator with an existing type like so.
It works, seemingly, but I'm sure this is not resilient; would be nice if someone can clean this up.
type ExistingTypeA = {
id: string
SomeNestedProperty: Array<ExistingTypeB>
}
MyValidatorThing: zod.custom<ExistingTypeA>( (value:any) => value && value.SomeNestedProperty && value.SomeNestedProperty.some( (x:ExistingTypeB) => { return x.SomeKey === 'SomeValue' }))
Notes:
1 - I don't like the value:any
. I would like to of course use value:ExistingTypeA
but then I get an IDE TS warning:
Argument of type '(value: ExistingTypeA) => boolean' is not assignable to parameter of type '(data: unknown) => any'.
Types of parameters 'value' and 'data' are incompatible.
Type 'unknown' is not assignable to type 'ExistingTypeA'.ts(2345)
... so, using value:any
to pass that hurdle in the meantime.
2 - Consequently, when the validator (MyValidatorThing) triggers in the browser (runtime), errors occur in the console: " "value is not found" if input is empty, or "value.SomeNestedProperty not found" if attempting to submit an object of an entirely different type.
To clear these runtime errors, I added the extra value &&
and value.SomeNestedProperty &&
which seems to account for these cases (no-value or wrong-value-object-type).
In testing, so far this validator works and I get my custom logic (checking a nested property).
I'm sure this isn't rock-solid though, esp with an :any
in there.
the current example is not very good, because it could easily be solved with z.string().regex(). https://github.com/colinhacks/zod#custom-schemas
I would like an example where you can't solve it easily with another zod schema.