I'm having a hard time understanding how discriminated union work.
I have this schema bellow and I have a couple of conditions:
One is for the workStatus this is required. The user has 3 options, "Full Time", "Contract" and "Both"
Now based on what the user selects we must display the appropriate fields
=> User selects "Full Time" then we need to request for fullTimeCompensation and contractCompensation should be undefined
=> User selects 'Contract" then we need to request for 'contractCompensationandfullTimeCompensationshould be undefined => User selects 'Both" then we need to request forfullTimeCompensation and 'contractCompensation
The other condition is workLocationType, this is a required field and the user has two options, either "Remote" or "Flexible"
If the user selects "Flexible" we need to as for field acceptableTravelTime, if user selects "Remote" then acceptableTravelTime should be undefined.
This is how I've defined my schemas
const workStatusEnumSchema = z.nativeEnum(Work_Status_Types_Enum, {
errorMap: () => ({ message: formValidationMessages.format('fieldRequired') }),
})
const workLocationEnumSchema = z.nativeEnum(Work_Location_Types_Enum, {
errorMap: (issue, _ctx) => {
console.warn('issue', issue)
console.warn('context', _ctx)
return { message: formValidationMessages.format('fieldRequired') }
},
})
const workVacationEnumSchema = z.nativeEnum(Work_Vacation_Durations_Enum, {
errorMap: () => ({ message: formValidationMessages.format('fieldRequired') }),
})
const baseSchema = z.object({
workStatus: workStatusEnumSchema,
workLocationType: workLocationEnumSchema,
vacationDuration: workVacationEnumSchema,
address: z.string(),
latitude: z.number(),
longitude: z.number(),
drivingToWork: z.boolean(),
occasionallyTravelOffice: z.boolean(),
relocateForWork: z.boolean(),
visaSponsorShip: z.array(visaSponsorshipSchema),
spokenLanguages: z.array(optionSchema),
})
const fullTimeSchema = baseSchema.extend({
workStatus: z.literal(Work_Status_Types_Enum.FullTime),
fullTimeCompensation: z.string({
required_error: formValidationMessages.format('fieldRequired'),
}),
contractCompensation: z.undefined(),
})
const contractSchema = baseSchema.extend({
workStatus: z.literal(Work_Status_Types_Enum.Contract),
contractCompensation: z.string({
required_error: formValidationMessages.format('fieldRequired'),
}),
fullTimeCompensation: z.undefined(),
})
const fullTimeContractSchema = baseSchema.extend({
workStatus: z.literal(Work_Status_Types_Enum.FullTimeOrContract),
contractCompensation: z.string({
required_error: formValidationMessages.format('fieldRequired'),
}),
fullTimeCompensation: z.string({
required_error: formValidationMessages.format('fieldRequired'),
}),
})
const workStatusSchema = z.union([fullTimeSchema, contractSchema, fullTimeContractSchema])
const flexibleSchema = baseSchema.extend({
workLocationType: z.literal(Work_Location_Types_Enum.Flexible),
acceptableTravelTime: z.string({
required_error: formValidationMessages.format('fieldRequired'),
}),
})
const remoteSchema = baseSchema.extend({
workLocationType: z.literal(Work_Location_Types_Enum.Remote),
acceptableTravelTime: z.undefined(),
})
const workLocationSchema = z.union([flexibleSchema, remoteSchema])
const schema = z.union([baseSchema, workLocationSchema, workStatusSchema])
type FormData = z.infer<typeof schema>
const methods = useForm<FormData>({
mode: 'onBlur',
reValidateMode: 'onBlur',
defaultValues: {
vacationDuration: '' as Work_Vacation_Durations_Enum,
workLocationType: '' as Work_Location_Types_Enum,
workStatus: '' as Work_Status_Types_Enum,
address: '',
drivingToWork: false,
occasionallyTravelOffice: false,
relocateForWork: false,
visaSponsorShip: [],
spokenLanguages: [
buildSpokenLanguageOption(router.locale as string, spokenLanguagesMessages),
],
},
resolver: zodResolver(schema),
})
At this point I have no errors in the schema nor in the default values.
However, in my onSubmit function which is defined as follow:
const onSubmit = async ({
vacationDuration,
workLocationType,
workStatus,
fullTimeCompensation,
contractCompensation,
acceptableTravelTime,
address,
latitude,
longitude,
drivingToWork,
relocateForWork,
visaSponsorShip,
occasionallyTravelOffice,
spokenLanguages,
}: FormData): Promise<void> => {
...
}
But this clearly doesn't work. If a user selects 'Full Time" then I get an error "Expeted 'CONTRACT', received 'FULL_TIME'", and in fullTimeCompensation if the user enters a value he get's an error "Expected undefined, received 'string'". Same thing if the user selects 'CONTRACT' and same behaviour for workLocationType if user selects something else other than "REMOTE" he will get the same error.
I'm not sure how to create the schema for my use case :(
Any help would be greatly appreciated.
I'm having a hard time understanding how discriminated union work.
I have this schema bellow and I have a couple of conditions:
One is for the
workStatusthis is required. The user has 3 options, "Full Time", "Contract" and "Both"Now based on what the user selects we must display the appropriate fields
=> User selects "Full Time" then we need to request for
fullTimeCompensationandcontractCompensationshould be undefined=> User selects 'Contract" then we need to request for 'contractCompensation
andfullTimeCompensationshould be undefined => User selects 'Both" then we need to request forfullTimeCompensationand 'contractCompensationThe other condition is
workLocationType, this is a required field and the user has two options, either "Remote" or "Flexible"If the user selects "Flexible" we need to as for field
acceptableTravelTime, if user selects "Remote" thenacceptableTravelTimeshould be undefined.This is how I've defined my schemas
At this point I have no errors in the schema nor in the default values.
However, in my
onSubmitfunction which is defined as follow:But this clearly doesn't work. If a user selects 'Full Time" then I get an error "Expeted 'CONTRACT', received 'FULL_TIME'", and in
fullTimeCompensationif the user enters a value he get's an error "Expected undefined, received 'string'". Same thing if the user selects 'CONTRACT' and same behaviour forworkLocationTypeif user selects something else other than "REMOTE" he will get the same error.I'm not sure how to create the schema for my use case :(
Any help would be greatly appreciated.