Skip to content

collection().columns should allow array fields (runtime works, types reject them) #1548

Description

@tordans

Problem

We want to show an array field in a collection list view via the columns option. For example, a list of external project slugs so editors can see at a glance which entries are linked to another system:

steckbriefe: collection({
  label: 'Steckbriefe',
  slugField: 'slug',
  path: 'src/data/steckbriefe/*/',
  format: { data: 'yaml' },
  columns: ['title', 'state', 'trassenscoutProjectSlugs', 'lastCheckedDate'],
  schema: {
    title: fields.text({ label: 'Titel', validation: { isRequired: true } }),
    trassenscoutProjectSlugs: fields.array(fields.text({ label: 'Trassenscout slug' }), {
      label: 'Trassenscout',
      itemLabel: (props) => props.value || 'Slug',
    }),
    // ...
  },
}),

Runtime: This works. The Admin UI renders array column values by stringifying them (val + ''), so ['rs8', 'rs8-north'] shows as rs8,rs8-north and [] shows as empty.

Types: TypeScript rejects trassenscoutProjectSlugs in columns because collection() only allows keys whose schema field is a scalar FormField or SlugFormField:

// dist/declarations/src/config.d.ts (current)
columns?: {
  [K in keyof Schema]: Schema[K] extends
    | FormField<any, any, string | number | boolean | Date | null | undefined>
    | SlugFormField<any, any, any, string>
    ? K & string
    : never;
}[keyof Schema][];

ArrayField (kind: 'array') is excluded even though the list view handles it fine.

Expected behavior

Array fields should be valid in columns, since the collection table already displays them.

Actual behavior

  • Admin UI: works
  • TypeScript: error — Type '"trassenscoutProjectSlugs"' is not assignable to type ...

Suggested fix

Extend the columns mapped type to also allow ArrayField keys:

columns?: {
  [K in keyof Schema]: Schema[K] extends
    | FormField<any, any, string | number | boolean | Date | null | undefined>
    | SlugFormField<any, any, any, string>
    ? K & string
    : Schema[K] extends { kind: 'array' }
      ? K & string
      : never;
}[keyof Schema][];

Environment

  • @keystatic/core: 0.5.50
  • @keystatic/astro: 5.1.0
  • TypeScript: 6.x
  • Package manager: Bun 1.3

Workarounds (until upstream fix)

Option A: @ts-expect-error (minimal)

steckbriefe: collection({
  // Keystatic renders array columns as comma-separated values; types only allow scalars.
  // @ts-expect-error array field used as list column
  columns: ['title', 'state', 'trassenscoutProjectSlugs', 'lastCheckedDate'],
  schema: {
    trassenscoutProjectSlugs: fields.array(fields.text({ label: 'Trassenscout slug' }), {
      label: 'Trassenscout',
    }),
    // ...
  },
}),

Option B: Patch @keystatic/core (what we use)

We patch the published type definition so columns accepts array fields without suppressions.

1. Start a patch (Bun):

bun patch @keystatic/core

2. Edit node_modules/@keystatic/core/dist/declarations/src/config.d.ts:

     columns?: {
-        [K in keyof Schema]: Schema[K] extends FormField<any, any, string | number | boolean | Date | null | undefined> | SlugFormField<any, any, any, string> ? K & string : never;
+        [K in keyof Schema]: Schema[K] extends FormField<any, any, string | number | boolean | Date | null | undefined> | SlugFormField<any, any, any, string> ? K & string : Schema[K] extends {
+            kind: 'array';
+        } ? K & string : never;
     }[keyof Schema][];

3. Commit the patch:

bun patch --commit 'node_modules/@keystatic/core'

This creates patches/@keystatic%2Fcore@0.5.50.patch and adds to package.json:

"patchedDependencies": {
  "@keystatic/core@0.5.50": "patches/@keystatic%2Fcore@0.5.50.patch"
}

Bun reapplies the patch on every bun install. After upgrading @keystatic/core, regenerate the patch for the new version.

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