#Optional fields

18 messages · Page 1 of 1 (latest)

maiden belfry
#

Hi guys, I have a question about Tanstack Form.

const schema = z.object({
    name: z.string().min(2, 'Name must be at least 2 characters long'),
    email: z.string().email('Invalid email address').optional(),
    age: z.coerce.number().min(18, 'You must be at least 18 years old')
})

const TanstackFormExample = () => {
    const form = useForm({
        defaultValues: {
            name: '',
            email: '',
            age: 12
        },
        validators: {
            onChange: schema
        },
        onSubmit: ({ value }) => {
            console.log(value)
        }
    })

You can see that email is optional. But when I do it like this, the line onChange: schema starts firing an error sayng The types of ''~standard'.types' are incompatible between these types.. What is the best approach to handle optional fields?

Someone suggested casting the default values like this:

        defaultValues: {
            name: '',
            email: undefined,
            age: 12
        } as z.input<typeof schema>,

But I don't really like casting and I feel like there should be a nicer solution to have some fields optional

slow sable
#

I don't really like casting

me neither but here it's the way to go

shy glen
#

for zod specifically, you can use the fact that input and output are different types to have a better experience with tanstack form

maiden belfry
#

Feels weird when of the selling points of Tanstack form was that you don't need to provide generics and yet you need to cast to make it work with optional fields

maiden belfry
shy glen
maiden belfry
#

Connected to this issue - when I remove the default values altogether:

    const form = useForm({
        validators: {
            onSubmit: schema
        },
        onSubmit: ({ value }) => {
            console.log(value)
        }
    })

The value inside onSubmit is of type unknown. I would expect it to infer the value based on the result of the validator. Am I doing something wrong or are default values required at all times?

shy glen
#

defaultValues tell the form how to populate its data, so you should always pass it

maiden belfry
#

Well yes, but sometimes you need some default values to be undefined. I would expect the form lib to infer the types based on the validator function, and not on the default values, as they are many times different from what I want in the output

shy glen
# maiden belfry Well yes, but sometimes you need some default values to be undefined. I would ex...

If the input values are different than your desired output values, that's what zod (and other standard schema libraries) can work well with:

/**
 * Modifies the provided schema to be nullable on input, but non-nullable on output.
 */
export function nullableInput<TSchema extends ZodTypeAny>(schema: TSchema) {
  return schema.nullable().transform((value, ctx: RefinementCtx) => {
    if (value === null) {
      ctx.addIssue({
        code: z.ZodIssueCode.invalid_type,
        expected: z.getParsedType(schema),
        received: z.ZodParsedType.null,
      });
      return z.NEVER;
    }
    return value;
  });
}
#
selectedPerson: nullableInput(z.string())
maiden belfry
#

Yes, this proves my point - when I have it like this, the only type that is used is the InputType, and not the OutputType. I would expect that after submit validation, I would have the value being OutputType.

const schema = z.object({
    name: z.string().min(2, 'Name must be at least 2 characters long'),
    email: nullableInput(z.string().email('Invalid email address')),
    age: z.coerce.number().min(18, 'You must be at least 18 years old')
})

type InputType = z.input<typeof schema>
type OutputType = z.infer<typeof schema>

const TanstackFormExample = () => {
    const defaultValues: InputType = {
        name: '',
        email: null,
        age: 12
    }

    const form = useForm({
        defaultValues,
        validators: {
            onSubmit: schema
        },
        onSubmit: ({ value }) => {
  ----------------------------------------------------------------------
    // Value is of type InputType, instead of OutputType
  ----------------------------------------------------------------------
        }
    })
shy glen
#

I think it was because field validators could override form level validators

#

which could maybe cause conflicts? idk. Point is you get the input type on submit

maiden belfry
#

Shame, It would be so much nicer