Summary
A native list/array scalar column — a field typed readonly T[] where T is a primitive/enum (string), not an entity — is dropped from every branch of the accessor field-type mapping. The accessor proxy exposes no FieldAccessor for it, so .value / .setValue don't exist on the type and reading/writing the column from createComponent explicit selection fails to compile. The runtime FieldHandle handles array columns fine; only the types are wrong.
Environment
Reproduction
A Contember enumColumn(...).list() (or any .list() scalar) generates an entity field typed as readonly T[] with T a string enum:
import type { ScalarKeys, FieldAccessor, EntityAccessor } from '@contember/bindx-react'
type AssertExtends<T, U> = [T] extends [U] ? true : false
function assertTrue<T extends true>(): void {}
interface Lesson {
id: string
title: string
// native list/array SCALAR column — array of a string enum, not a relation
groupSize: readonly ('whole' | 'group' | 'individual')[]
}
// FAILS: groupSize is not in ScalarKeys<Lesson> (which is only 'id' | 'title')
assertTrue<AssertExtends<'groupSize', ScalarKeys<Lesson>>>()
type LessonAcc = EntityAccessor<Lesson, { groupSize: readonly string[] }>
type GroupSizeField = LessonAcc['$fields']['groupSize']
// FAILS: the field is not a FieldAccessor, so it has no .value / .setValue
assertTrue<AssertExtends<GroupSizeField, FieldAccessor<readonly string[]>>>()
Both assertTrue lines error with TS2344: Type 'false' does not satisfy the constraint 'true'.
Expected behavior
An array-valued scalar column is still a scalar field — it should be classified as a ScalarKeys member and its accessor should be FieldAccessor<readonly T[]>, with .value returning the array and .setValue(next) replacing it. (FieldRefMeta already carries an isArray flag, so the model anticipates array fields.)
Actual behavior
The field is excluded from all three key sets in packages/bindx/src/handles/types.ts:
ScalarKeys<T> (lines ~53–61): T[K] extends (infer _U)[] ? never : … — any array-valued field is excluded outright.
HasManyKeys<T> (lines ~63–69): T[K] extends (infer U)[] ? U extends object ? K : never : never — an array of a non-object element is excluded.
HasOneKeys<T> (lines ~71–79): excluded because it IS an array.
EntityFieldsAccessor then maps only over (ScalarKeys | HasManyKeys | HasOneKeys) & keyof TSelected, so the column has no entry and resolves through the base proxy intersection to a HasOne-style accessor with no .value / .setValue.
Suspected root cause
ScalarKeys<T> treats "is an array" as "is not a scalar". For columns this is wrong: a .list() scalar column is array-valued but is still a column, not a relation. HasManyKeys only matches arrays of objects (entities), so array-of-primitive columns fall through every branch.
Suggested fix
Make ScalarKeys<T> keep array-valued keys whose element is not an object (i.e. scalar arrays), and ensure FieldAccessorType / EntityFieldsAccessor route them to FieldAccessor<TEntity[K]>. Roughly: in ScalarKeys, an array key should be never only when its element extends object (that's a has-many); a scalar-element array stays a scalar key. The runtime FieldHandle already supports array columns, so this is a type-only change in packages/bindx/src/handles/types.ts. Maintainers may prefer a dedicated ScalarArrayKeys branch — deferring the exact shape to you.
Workaround shipped downstream
We applied a temporary workaround in our project, marked
TODO [BindX] (<this-issue-url>): …. The workaround narrows the list-enum field accessor to a precise local interface exposing value/setValue (no as any) at the two read/write sites in the material corrector form; we will remove it once this issue is resolved.
Summary
A native list/array scalar column — a field typed
readonly T[]whereTis a primitive/enum (string), not an entity — is dropped from every branch of the accessor field-type mapping. The accessor proxy exposes noFieldAccessorfor it, so.value/.setValuedon't exist on the type and reading/writing the column fromcreateComponentexplicit selection fails to compile. The runtimeFieldHandlehandles array columns fine; only the types are wrong.Environment
@contember/bindx@0.1.43(version installed in the reporting project)contember/bindx@mainas of6f3c2f1tests/typeSafety.test.ts(theType Safety - list/array scalar columnsdescribe block — compile-time assertions)bug/list-enum-scalar-column-not-typed-as-field-accessorReproduction
A Contember
enumColumn(...).list()(or any.list()scalar) generates an entity field typed asreadonly T[]withTa string enum:Both
assertTruelines error withTS2344: Type 'false' does not satisfy the constraint 'true'.Expected behavior
An array-valued scalar column is still a scalar field — it should be classified as a
ScalarKeysmember and its accessor should beFieldAccessor<readonly T[]>, with.valuereturning the array and.setValue(next)replacing it. (FieldRefMetaalready carries anisArrayflag, so the model anticipates array fields.)Actual behavior
The field is excluded from all three key sets in
packages/bindx/src/handles/types.ts:ScalarKeys<T>(lines ~53–61):T[K] extends (infer _U)[] ? never : …— any array-valued field is excluded outright.HasManyKeys<T>(lines ~63–69):T[K] extends (infer U)[] ? U extends object ? K : never : never— an array of a non-object element is excluded.HasOneKeys<T>(lines ~71–79): excluded because it IS an array.EntityFieldsAccessorthen maps only over(ScalarKeys | HasManyKeys | HasOneKeys) & keyof TSelected, so the column has no entry and resolves through the base proxy intersection to a HasOne-style accessor with no.value/.setValue.Suspected root cause
ScalarKeys<T>treats "is an array" as "is not a scalar". For columns this is wrong: a.list()scalar column is array-valued but is still a column, not a relation.HasManyKeysonly matches arrays of objects (entities), so array-of-primitive columns fall through every branch.Suggested fix
Make
ScalarKeys<T>keep array-valued keys whose element is not an object (i.e. scalar arrays), and ensureFieldAccessorType/EntityFieldsAccessorroute them toFieldAccessor<TEntity[K]>. Roughly: inScalarKeys, an array key should beneveronly when its element extendsobject(that's a has-many); a scalar-element array stays a scalar key. The runtimeFieldHandlealready supports array columns, so this is a type-only change inpackages/bindx/src/handles/types.ts. Maintainers may prefer a dedicatedScalarArrayKeysbranch — deferring the exact shape to you.Workaround shipped downstream
We applied a temporary workaround in our project, marked
TODO [BindX] (<this-issue-url>): …. The workaround narrows the list-enum field accessor to a precise local interface exposingvalue/setValue(noas any) at the two read/write sites in the material corrector form; we will remove it once this issue is resolved.