[Help/Question] Function with optional parameters, ZodError: "too_small" #949
-
Perhaps I'm misunderstanding how this works, but I have made the following function: const formatCurrency = z
.function()
.args(
z.number(),
z.string().optional(),
z.string().optional(),
)
.returns(z.string())
.implement((value: number, currency: string = 'CAD', locale: string = 'en-CA'): string => {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency,
minimumFractionDigits: 0,
maximumFractionDigits: 0
}).format(value);
}); It works when I call ZodError: [
{
"code": "invalid_arguments",
"argumentsError": {
"issues": [
{
"code": "too_small",
"minimum": 3,
"inclusive": true,
"type": "array",
"path": [],
"message": "Should have at least 3 items"
}
],
"name": "ZodError"
},
"path": [],
"message": "Invalid function arguments"
}
] What is the correct way to handle optional arguments? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Explanation
Most of the time, This is essentially what you are doing: const args = z.tuple( [
z.number(),
z.string().optional(),
z.string().optional(),
] )
console.log( args.safeParse( [ 42, 'CAD', 'en-CA' ] ).success ) // true
console.log( args.safeParse( [ 42, undefined, undefined ] ).success ) // true
console.log( args.safeParse( [ 42 ] ).success ) // false This is pretty confusing. But if zod were to change this, it might break backwards compatibility. I'm not trying to say that zod shouldn't change this, rather that I'm not sure zod will. SolutionI would suggest changing your args into an object for this instead. I find using an object is much easier to deal with optional args, but it also has a few other benefits. Such as, it's easier to understand which arg is what when you come back to this code later. Also, it allows for you to put the args in any order. const formatCurrency = z
.function()
.args(
z.object( {
value: z.number(),
currency: z.string().optional(),
locale: z.string().optional(),
} )
)
.returns( z.string() )
.implement( ( { value, currency = 'CAD', locale = 'en-CA' } ): string => {
return new Intl.NumberFormat( locale, {
style: 'currency',
currency,
minimumFractionDigits: 0,
maximumFractionDigits: 0
} ).format( value )
} )
console.log( formatCurrency( { value: 42, currency: 'CAD', locale: 'en-CA' } ) ) // $42
console.log( formatCurrency( { currency: 'CAD', locale: 'en-CA', value: 42 } ) ) // $42
console.log( formatCurrency( { value: 42 } ) ) // $42 |
Beta Was this translation helpful? Give feedback.
Explanation
optional
in zod doesn't mean optional the way you might think. All it means is that the value can beundefined
.undefined
doesn't always mean non-existent. It is a little confusing, yes.Most of the time,
optional
works the same as how you would expect, but in the case of functionargs
ortuples
, saying that it'soptional
just means that it needs to exist, but it can beundefined
.This is essentially what you are doing: