ResolveA2uiProp<ChildList> resolves to any, so props.children is any in every component implementation whose schema uses ChildListSchema.
See also #1296. any/unknown makes code brittle and more cognitively burdensome to reason about. It can even cause LLMs to get confused, e.g. https://github.com/google/A2UI/pull/1510/changes#r3331738566.
Both renderers cast around it locally:
(Angular isn't affected as it rolls its own data binding, not using GenericBinder and thus ResolveA2uiProp)
Fix
Define ResolvedChildRef and ResolvedChildList matching what the binder actually emits:
export type ResolvedChildRef =
| ComponentId
| {id: ComponentId; basePath: string};
Then, we either
- fix
ResolveA2uiProp, which is the clean fix but could theoretically break customer builds at the typechecking step:
export type ResolveA2uiProp<T> = [NonNullable<T>] extends [Action]
? (() => void) | Extract<T, undefined>
: [NonNullable<T>] extends [ChildList]
- ? any | Extract<T, undefined>
+ ? ResolvedChild[] | Extract<T, undefined>
: Exclude<T, DynamicTypes> extends never
? any
: Exclude<T, DynamicTypes>;
or
- just define
ResolvedChildRef within the renders so at least the renderer code is more readable.
ResolveA2uiProp<ChildList>resolves toany, soprops.childrenisanyin every component implementation whose schema usesChildListSchema.See also #1296.
any/unknownmakes code brittle and more cognitively burdensome to reason about. It can even cause LLMs to get confused, e.g. https://github.com/google/A2UI/pull/1510/changes#r3331738566.Both renderers cast around it locally:
ChildList.tsx: acceptsunknown, later casting each element to{id: string; basePath?: string}:https://github.com/google/A2UI/blob/ade478faf8dcad611b5efb6b864dcbfbc4a51f68/renderers/react/src/v0_9/catalog/basic/components/ChildList.tsx#L21
Row.ts/Column.ts/List.tsusesany: https://github.com/google/A2UI/blob/ade478faf8dcad611b5efb6b864dcbfbc4a51f68/renderers/lit/src/v0_9/catalogs/basic/components/List.ts#L52(Angular isn't affected as it rolls its own data binding, not using
GenericBinderand thusResolveA2uiProp)Fix
Define
ResolvedChildRefandResolvedChildListmatching what the binder actually emits:Then, we either
ResolveA2uiProp, which is the clean fix but could theoretically break customer builds at the typechecking step:or
ResolvedChildRefwithin the renders so at least the renderer code is more readable.