Skip to content

Typegen incorrect for named array members references #11147

@fragglebob

Description

@fragglebob

Describe the bug

We use are using named array members references (not sure what the right term is) in our project, alongside object array members. For a mix of reusable module and inline modules on a page. That's all working fine but the typegen is incorrect for the query, all the references in the types have a _type of reference, that is not what comes back in the query. So there is some mismatch between the query result and generated type.

To Reproduce

Here's an slimed down example of our field definition.

defineField({
    name: 'modules',
    title: 'Modules',
    type: 'array',
    of: [
        defineArrayMember({ type: 'reference', name: 'accordionModuleDoc', to: [{ type: 'accordionModuleDoc' }] }),
        defineArrayMember({ type: 'reference', name: 'structuredTextModuleDoc', to: [{ type: 'structuredTextModuleDoc' }] }),
        defineArrayMember({ type: 'reference', name: 'heroModuleDoc', to: [{ type: 'heroModuleDoc' }] }),
        // ... Other reference types here
        defineArrayMember({ type: 'accordionModuleObject' }),
        defineArrayMember({ type: 'statModuleObject' }),
    ],
})

We fetch this content with a bit query like this:

export const PageQuery = defineQuery(`$[_type == "productPage" && slug.current == $slug]{
    modules[] {
        _type,
        _type == "accordionModuleDoc" => @ -> {
           // select fields
        },
        _type == "structuredTextModuleDoc" => @ -> {
            // select fields
        },
        _type == "heroModuleDoc" => @ -> {
            // select fields
        },
        _type == "accordionModuleObject" => {
            // select fields
        },
        _type == "statModuleObject" => {
            // select fields
        },
    }
}`)

So when selecting each module _type in the query, it's either the name of the type from the object, or the name defined on the array member, the query works fine.

But the type generate as something like:

export type PageQueryResult = {
    modules: Array<{
        _type: "accordionModuleObject",
       // other fields
    } | {
        _type: "statModuleObject",
       // other fields
    } | { _type: "reference" }>
} | null;

Expected behavior

The type should be something closer to this, as it would match better the the result of the query.

export type PageQueryResult = {
    modules: Array<{
        _type: "accordionModuleObject",
       // other fields
    } | {
        _type: "statModuleObject",
       // other fields
    } | {
        _type: "accordionModuleDoc",
       // other fields
    } |  {
        _type: "structuredTextModuleDoc",
       // other fields
    } | {
        _type: "heroModuleDoc",
       // other fields
    } | >
} | null;

Which versions of Sanity are you using?

@sanity/asset-utils                     2.3.0 (up to date)
@sanity/code-input                      6.0.3 (up to date)
@sanity/color-input                     4.0.6 (up to date)
@sanity/document-internationalization   4.1.0 (up to date)
@sanity/eslint-config-studio            5.0.2 (up to date)
@sanity/icons                           3.7.4 (up to date)
@sanity/schema                         4.11.0 (latest: 4.15.0)
@sanity/ui                             3.1.11 (up to date)
@sanity/vision                         4.11.0 (latest: 4.15.0)
sanity                                 4.11.0 (latest: 4.15.0)

What operating system are you using?

MacOS 26.1

Which versions of Node.js / npm are you running?

10.9.3
v22.19.0

Additional context

I have a feeling this is more down the to the schema generation, instead of the typegen. In the schema file, the _type attribute, for the named array members that are references, is a string with the value "reference", but if I change that to the name assigned to the array member, the types generate correctly after that.

I'm not sure what the consequence of that would be, but it seems to be solving my problem, so I have a patch I'm applying locally in my repo to @sanity/schema to apply this automatically.

function createArray(arraySchemaType) {
    const of = [];
    for (const item of arraySchemaType.of) {
      const field = convertSchemaType(item);
      field.type === "inline" ? of.push({
        type: "object",
        attributes: {
          _key: createKeyField()
        },
        rest: field
      }) : (field.type === "object" && (field.rest = {
        type: "object",
        attributes: {
          _key: createKeyField()
        }
      }), of.push(field));
+      if (field.type === "object" && field.attributes?._type?.value?.value === "reference" && item.name) {
+        field.attributes._type.value.value = item.name;
+      }
    }
    return of.length === 0 ? { type: "null" } : {
      type: "array",
      of: of.length > 1 ? {
        type: "union",
        of
      } : of[0]
    };
  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions