Reusable AppField components with unions
I have a multi-step form that's used for a union of data types that I'm discriminating by using a zod discriminated union schema. I've used this schema with .parse({}) to set up the default values and typescript. All of that works great. I use the form.Subscribe to get the values and use the values and the discriminator property to conditionally show fields. Awesome. Now, the issue I'm having is that the field values are not picking up the typing based on that narrowing. I'm not sure if I'm just doing something wrong. Here's the field in particular where I'm having the issue
Now when I use it in my form like so, I get a type error for my value that it's type "unknown" and I'm fairly certain it's because my field isn't picking up the values type narrowing which makes sense. Is there a way I can make it know that the state of the form was narrowed down somehow? Or do I just have to assert the type?
4 Replies
causal-orange•3mo ago
Can you open a minimal repro for this? Union types are tricky, but we'll look into it once it's a GH issue
Sorry about this
fair-roseOP•3mo ago
Sure can! No need to be sorry. I may just be using it wrong lol
Ok, I think I have something that works as reproducible. In the Step1.tsx file you can by hovering over values in the console log that it did indeep type narrow which is great. But, even when not narrowed, a shared property like label is still shown as value unknown in the validator. I'm willing to bet that's just the nature of these reusable app field components because I'm not sure how else they would get the correct typings since they're reliant on the useFieldContext which is - I assume - at run time not compile time. But, I'm almost very much still learning so I could be way off. In any case, here's the codesandbox link.
causal-orange•3mo ago
Let's make a GH issue with the CSB if that's okay 🙂
fair-roseOP•3mo ago
Posting here as I figured out the issue and it wasn't Tanstack Form.
I didn't realize that creating the schemas as functions with Zod was making my types loosely typed. It was adding "[x: string]: unknown" properties making anything I type a possibility. I've since corrected that. If anyone else is having issues, create each schema object as a plain object then convert to a zod object for the actual schema like this (you can ignore the defaults if you don't need it):
export const genericTypeInputObject: Properties = {
__kind: z.literal('GenericTypeInput'),
id: z.string().default(""),
value: z.string().default(""),
label: z.string().default(""),
desc: z.string().nullish().default(null),
tooltip: z.string().nullish().default(null),
short: z.string().nullish().default(null),
}
export const GenericTypeInputSchema = z.object(genericTypeInputObject)
export type GenericTypeInputInfer = z.infer
Then use that Schema object for the discriminated union. I tested this in a new code sandbox and it fixed the issue.