You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Observation, filed unassigned while correcting the BaseSchema common-props table for #7079. This is a declaration question, not a docs question, so it is filed rather than decided. The docs correction went ahead on its own footing: the table documents BaseSchema, and BaseSchema is what a node gets when its own schema does not restate the key.
What was measured
Read off packages/types/src/** on origin/main at 592acafbe, excluding __tests__ and zod/. Each <key>?: declaration was attributed to its enclosing exported interface, and that interface checked for extends BaseSchema.
124 interfaces extend BaseSchema. Of those, the number that redeclare an inherited member more narrowly than the base union:
base member
base declaration
extenders that narrow it
narrowed to
visible
boolean | string
0
—
disabled
boolean | string
18
boolean
label
string | I18nLabel
29
string (4 of them required)
description
string | I18nLabel
32
string
ariaLabel
string | KeyedI18nLabel
1
string (PageNodeSchema)
The 18 narrowing disabled: ActionSchema (crud.ts:89), CollapsibleSchema (disclosure.ts:109), ToggleGroupSchema (disclosure.ts:173), and fifteen in form.ts — ButtonSchema, InputSchema, TextareaSchema, SelectSchema, CheckboxSchema, RadioGroupSchema, SwitchSchema, ToggleSchema, SliderSchema, FileUploadSchema, DatePickerSchema, CalendarSchema, InputOTPSchema, FormSchema, ComboboxSchema.
A further 13 declarations of disabled?: boolean sit on shapes that do not extend BaseSchema at all (ListItem, NavLink, ButtonGroupButton, SelectOption, RadioOption, FormField, ComboboxOption, SelectOptionMetadata, MenuCommandItem, AccordionItem, ToggleGroupItem, TabItem) plus ColorPalette.disabled?: string, an unrelated colour-token vocabulary. Those are independent declarations, not narrowings, and are counted separately on purpose.
Control: the census attributes BaseSchema's own disabled?: boolean \| string to BaseSchema and excludes it from the narrowing count.
Why the asymmetry is the finding, not the narrowing
visible and disabled are twins by construction. Both were widened to boolean | string by #4581 on the same evidence — the renderer does not read either key as a boolean, it passes both to evaluator.evaluateCondition, declared (condition: string | boolean | undefined, context?) => boolean. base.ts:320-325 records that the previous asymmetry between them was "accidental rather than deliberate" (ruling #4580 Q3-A).
Yet after the widening, every concrete schema left visible alone and 18 narrowed disabled back. So a predicate string on visible is accepted everywhere, and the same predicate on disabled is a type error on eighteen of the most commonly authored schemas — ButtonSchema, InputSchema, SelectSchema, FormSchema among them. Nothing found in the tree rules on this; it looks like the narrowings simply predate the widening and were never revisited.
Why it matters beyond tidiness
This is the shape that makes AI-authored metadata hard to get right. The published base type advertises a capability the renderer really implements, and eighteen of the most-used concrete schemas silently refuse it. An author — human or generated — who reads BaseSchema and writes disabled: "${data.status === 'locked'}" on an InputSchema gets a type error whose message points at the narrowed subtype, not at the ruling that widened the base. label (29) and description (32) carry the same shape at larger scale.
The corrected table on #7079 mitigates the reader-facing half with a note that a concrete schema may narrow an inherited member and its own declaration wins. That is honest, but it documents the inconsistency rather than resolving it.
The question, not the answer
Three coherent directions, deliberately not chosen here:
Drop the narrowings — the 18 (and 29, and 32) redeclarations go, the base union stands everywhere, and evaluateCondition handles what it already handles. Widest capability, largest diff, and it grants a predicate on schemas nobody has asked for one on.
Keep them and make it deliberate — record that narrowing to boolean is the house shape for concrete widgets and that the base union exists for the generic path. Then visible's 0-of-124 becomes the outlier to fix, not disabled's 18.
Observation, filed unassigned while correcting the
BaseSchemacommon-props table for #7079. This is a declaration question, not a docs question, so it is filed rather than decided. The docs correction went ahead on its own footing: the table documentsBaseSchema, andBaseSchemais what a node gets when its own schema does not restate the key.What was measured
Read off
packages/types/src/**onorigin/mainat592acafbe, excluding__tests__andzod/. Each<key>?:declaration was attributed to its enclosing exported interface, and that interface checked forextends BaseSchema.124 interfaces extend
BaseSchema. Of those, the number that redeclare an inherited member more narrowly than the base union:visibleboolean | stringdisabledboolean | stringbooleanlabelstring | I18nLabelstring(4 of them required)descriptionstring | I18nLabelstringariaLabelstring | KeyedI18nLabelstring(PageNodeSchema)The 18 narrowing
disabled:ActionSchema(crud.ts:89),CollapsibleSchema(disclosure.ts:109),ToggleGroupSchema(disclosure.ts:173), and fifteen inform.ts—ButtonSchema,InputSchema,TextareaSchema,SelectSchema,CheckboxSchema,RadioGroupSchema,SwitchSchema,ToggleSchema,SliderSchema,FileUploadSchema,DatePickerSchema,CalendarSchema,InputOTPSchema,FormSchema,ComboboxSchema.A further 13 declarations of
disabled?: booleansit on shapes that do not extendBaseSchemaat all (ListItem,NavLink,ButtonGroupButton,SelectOption,RadioOption,FormField,ComboboxOption,SelectOptionMetadata,MenuCommandItem,AccordionItem,ToggleGroupItem,TabItem) plusColorPalette.disabled?: string, an unrelated colour-token vocabulary. Those are independent declarations, not narrowings, and are counted separately on purpose.Control: the census attributes
BaseSchema's owndisabled?: boolean \| stringtoBaseSchemaand excludes it from the narrowing count.Why the asymmetry is the finding, not the narrowing
visibleanddisabledare twins by construction. Both were widened toboolean | stringby #4581 on the same evidence — the renderer does not read either key as a boolean, it passes both toevaluator.evaluateCondition, declared(condition: string | boolean | undefined, context?) => boolean.base.ts:320-325records that the previous asymmetry between them was "accidental rather than deliberate" (ruling #4580 Q3-A).Yet after the widening, every concrete schema left
visiblealone and 18 narroweddisabledback. So a predicate string onvisibleis accepted everywhere, and the same predicate ondisabledis a type error on eighteen of the most commonly authored schemas —ButtonSchema,InputSchema,SelectSchema,FormSchemaamong them. Nothing found in the tree rules on this; it looks like the narrowings simply predate the widening and were never revisited.Why it matters beyond tidiness
This is the shape that makes AI-authored metadata hard to get right. The published base type advertises a capability the renderer really implements, and eighteen of the most-used concrete schemas silently refuse it. An author — human or generated — who reads
BaseSchemaand writesdisabled: "${data.status === 'locked'}"on anInputSchemagets a type error whose message points at the narrowed subtype, not at the ruling that widened the base.label(29) anddescription(32) carry the same shape at larger scale.The corrected table on #7079 mitigates the reader-facing half with a note that a concrete schema may narrow an inherited member and its own declaration wins. That is honest, but it documents the inconsistency rather than resolving it.
The question, not the answer
Three coherent directions, deliberately not chosen here:
evaluateConditionhandles what it already handles. Widest capability, largest diff, and it grants a predicate on schemas nobody has asked for one on.booleanis the house shape for concrete widgets and that the base union exists for the generic path. Thenvisible's 0-of-124 becomes the outlier to fix, notdisabled's 18.Picking between these is a contract decision about what the published type promises, and it wants a maintainer ruling rather than a dev's judgement.
Refs #7079 · #6347 · #4581 · #4580.
Generated by Claude Code