Thinkmill / Thinkmill/keystatic

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

Open Beginner friendly
#1,548 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
2.4k
Forks
159
Avg merge
21h 41m
Merged PRs (30d)
2

Description

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.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the generated declaration in dist/declarations/src/config.d.ts and locate the source declaration for collection()'s columns option. Check the existing scalar and slug field type constraints, then verify that array fields are accepted while unsupported fields remain rejected. Confirm completion with the project's TypeScript checks or type-test suite, if available.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
developer-experience
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.