最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

reactjs - How to set empty string as defaultValue on optional number property? - Stack Overflow

programmeradmin0浏览0评论

I have a form field which may either have no input or it must contain a number.

Problem: Typescript complains about assigning an empty string "" as default value to my zod-typed property optionalNumber. My zod schema allows a "" literal or a number as input.

Unfortunately, when using react-hook-form with zod, you get a react console warning at runtime, that you should not convert controlled components into uncontrolled components, if you have zod attributes which did not get a default value assigned in React.useForm(). So I believe I must really assign a default value to my zod optionalNumber property.

My schema:

const mySchema = z.object(
  optionalNumber: z.literal('')
     .or(z.coerce.number())
     .transform(((val) => val === '' ? undefined : val)
)

Problem: Typescript warning when assigning "" as default value:

const form = useForm(z.infer<typeof mySchema>({
        resolver: zodResolver(mySchema),
        defaultValues: {
            optionalNumber: '' // TS2322: Type string is not assignable to type number
        }
    });

The cause of the warning appears to be the fact that the defaultValues parameter of React.useForm() considers the possible output type of zod parsing to be the allowed input type for the default value. Might be a fundamental issue, but I need to live in the react world that exists, not the one I would rather like ;-)

Is there a way to have a react-hook-form/zod number field, which gets initialized to have no input in the beginning, and can be submitted

  • either without input
  • or with a numeric input?

Note that the application does what I want, the problem is Typescript complaining about the wrong type of the default value of optionalNumber.

EDIT: as @super and @nicholas-dullam pointed out: once you use z.transform(), it is fundamental to distinguish input and output type, zod is perfectly able to do that with z.input<typeof mySchema> and urgently asks us to do so: /?id=type-inference.

Possible solution along these lines:

Zod Schema:

price: z.string().optional().transform((val) => {
    if(val === '' || typeof val === 'undefined') {
      return undefined;
    } else {
      return parseInt(val, 10);
    }
  }).refine((val) => 
      typeof val === 'undefined' || val >= 0, { 
          message: "Price must at least be 0"
  })

Setting '' as default value in React.useForm():

const form = useForm(
    z.input<typeof mySchema>({ // <== z.input does the trick
            resolver: zodResolver(mySchema),
            defaultValues: {
                optionalNumber: ''
            }
    });

I have a form field which may either have no input or it must contain a number.

Problem: Typescript complains about assigning an empty string "" as default value to my zod-typed property optionalNumber. My zod schema allows a "" literal or a number as input.

Unfortunately, when using react-hook-form with zod, you get a react console warning at runtime, that you should not convert controlled components into uncontrolled components, if you have zod attributes which did not get a default value assigned in React.useForm(). So I believe I must really assign a default value to my zod optionalNumber property.

My schema:

const mySchema = z.object(
  optionalNumber: z.literal('')
     .or(z.coerce.number())
     .transform(((val) => val === '' ? undefined : val)
)

Problem: Typescript warning when assigning "" as default value:

const form = useForm(z.infer<typeof mySchema>({
        resolver: zodResolver(mySchema),
        defaultValues: {
            optionalNumber: '' // TS2322: Type string is not assignable to type number
        }
    });

The cause of the warning appears to be the fact that the defaultValues parameter of React.useForm() considers the possible output type of zod parsing to be the allowed input type for the default value. Might be a fundamental issue, but I need to live in the react world that exists, not the one I would rather like ;-)

Is there a way to have a react-hook-form/zod number field, which gets initialized to have no input in the beginning, and can be submitted

  • either without input
  • or with a numeric input?

Note that the application does what I want, the problem is Typescript complaining about the wrong type of the default value of optionalNumber.

EDIT: as @super and @nicholas-dullam pointed out: once you use z.transform(), it is fundamental to distinguish input and output type, zod is perfectly able to do that with z.input<typeof mySchema> and urgently asks us to do so: https://zod.dev/?id=type-inference.

Possible solution along these lines:

Zod Schema:

price: z.string().optional().transform((val) => {
    if(val === '' || typeof val === 'undefined') {
      return undefined;
    } else {
      return parseInt(val, 10);
    }
  }).refine((val) => 
      typeof val === 'undefined' || val >= 0, { 
          message: "Price must at least be 0"
  })

Setting '' as default value in React.useForm():

const form = useForm(
    z.input<typeof mySchema>({ // <== z.input does the trick
            resolver: zodResolver(mySchema),
            defaultValues: {
                optionalNumber: ''
            }
    });
Share Improve this question edited Jan 20 at 14:22 dschulten asked Jan 19 at 18:19 dschultendschulten 3,1222 gold badges33 silver badges46 bronze badges 6
  • stackoverflow.com/q/76404196/743507 seems related considering the title, but the actual description discusses a different issue. Besides, it has no answers. – dschulten Commented Jan 19 at 18:24
  • 1 Have you tried using z.input instead of z.infer? – super Commented Jan 19 at 18:34
  • Unable to run and verify the code provided. This needs a complete minimal reproducible example. – Drew Reese Commented Jan 19 at 19:09
  • 1 Well it was reproducible enough that both @nicholas-dullam and "super" were able to spot my problem right away. Maybe you want to reconsider your downvote. Not everything needs a codesandbox, IMHO. – dschulten Commented Jan 20 at 7:10
  • Your code snippet had typos that needed to be addressed first, and since it was incomplete readers would need to guess dependency versions and imports. Getting your code example to a reproducible state is your responsibility, not ours, so be thankful others came along that understood well enough the problem to help. Please be aware of this the next time you post. I was eventually able to get it running and reproduced the issue and resolved it a different way, but because your post was so minimal I wasn't sure what your overall goal really was (other than to make TS happy). Cheers. – Drew Reese Commented Jan 21 at 8:09
 |  Show 1 more comment

1 Answer 1

Reset to default 2

z.infer<typeof schema> will always resolve to the output of the provided zod schema (z.output<typeof schema>). Using z.input<typeof schema> i.e. useForm<z.input<typeof schema>>(...) will resolve to your expected types.

发布评论

评论列表(0)

  1. 暂无评论