Combining sanity typegen with the generated slots.d.ts, one type system or two?
We use sanity typegen to type all our GROQ results, and now the Croct CLI has generated a slots.d.ts in the repo. So I have two generated type sources describing what is conceptually the same hero.
My component currently takes the typegen result:
type Props = {hero: HOME_HERO_QUERYResult};but the slot fetch returns its own payload type, and tsc is not happy when I try to pass one where the other is expected:
Type 'SlotContent<"home-hero@1">' is not assignable to type 'HOME_HERO_QUERYResult'. Types of property 'ctaLabel' are incompatible.How are people reconciling these? One shared type, an adapter, something else? And should slots.d.ts be committed or gitignored?
2 answers
Treat them as two type systems that meet at one interface: your component's props. Typegen describes what GROQ returns, slots.d.ts describes what the slot serves, and the component should accept a single shape both can satisfy.
The trick is to stop making the component depend on either generated type directly. Define the component props yourself (or derive them from SlotContent<'home-hero@1'> since that is the shape the live site actually renders), then align the two sources with it:
- On the Croct side, the slot's component schema defines the payload, so SlotContent<'home-hero@1'> matches by construction.
- On the Sanity side, project your GROQ query into the same keys. Your tsc error suggests the projections drifted (ctaLabel vs whatever the schema calls it). Fix the projection, not the component.
Once the fallback shape matches the slot's component schema, you pass the GROQ result as the fallback and the whole thing typechecks with one component type.
On your last question: commit slots.d.ts. The CLI regenerates it, but having it committed avoids an API fetch at build time, which you will appreciate the first time CI runs without network access to the Croct API.
Deriving props from SlotContent and fixing the GROQ projection did it, zero casts left. Committed the file too. Thanks.
One more thing since you are leaning on generated types: pin your slot versions in code, like 'home-hero@2', not just 'home-hero'. An unpinned ID resolves to @latest, so someone publishing a new schema version can change the payload shape under you while your committed slots.d.ts still describes the old one. Pinned versions keep the runtime payload and the generated types moving together, and you bump both deliberately when you upgrade.