#tanstack form type errors with a zod discriminated union

9 messages · Page 1 of 1 (latest)

inland lance
#

For context, here is my schema expressed in ts types for clarity js { engine_type: "Petrol" | "Petrol-LPG" | "Diesel" | "Mild Hybrid" | "Hybrid" | "Plug-in Hybrid"; manufacturer: string; model: string; variant: string; price: number; co2_min?: number | null | undefined; co2_max?: number | null | undefined; engine_displacement?: number | null | undefined; fuel_economy_min?: number | null | undefined; fuel_economy_max?: number | null | undefined; hp?: number | null | undefined; url?: string | null | undefined; } | { engine_type: "Electric"; manufacturer: string; model: string; variant: string; price: number; battery_capacity?: number | null | undefined; energy_consumption?: number | ... 1 more ... | undefined; battery_range?: number | ... 1 more ... | undefined; hp?: number | ... 1 more ... | undefined; url?: string | ... 1 more ... | undefined; } In my form the default value of engine_type is 'Petrol", so the 1st variant is used for type checking. I am using the form.Subscribe HOC to show only the relavant fields based on the engine_type. The type error manifests in the electric car only fields. Any idea how to get rid of the type error without casting?

gusty jacinth
#

what might be happening is two things:

  1. You're giving the defaultValues directly. TypeScript won't know it can be a union in this case, so it will complain.
  2. You're assigning defaultValues externally with the correct type. However, TypeScript thinks that, since defaultValues is never reassigned, it is only part of the union. It's a problem that has been around for a while, and neither satisfies or as can properly solve it.
type Animal = Dog | Cat;

const value: Animal = cat();
//    ^? Cat

// this also won't do, not type safe
const value = cat() as Animal;

// this doesn't change the type
const value = cat() satisfies Animal;
//    ^? Cat

// this does what you expect
const value = cat() satisfies Animal as Animal;

// Alternative approach
function identity<T>(obj: T): T { return T; }

const value = identity<Animal>(cat())
inland lance
#

I use the 2nd approach, external assignment

#

Satisfies + as combo works 🙂

gusty jacinth
#

for a quick check, satisfies X as X should "solve the types"

#

okay, yeah then it was that issue

#

as general note, you'll often see this problem pop up with string unions and assigning an initial one. An identity function never hurts to be around for type safety

#

An example from our workplace:

export function oneof<T = never>(value: T): T { return T; }