Found while measuring #4580 (the SchemaNode reconciliation, PR #4593). Filed rather than fixed — #4580's scope is SchemaNode, and this is a second, independent pair sitting in the same two files.
The pair
packages/core/src/types/index.ts:18
export interface ComponentRendererProps {
schema: SchemaNode;
[key: string]: any;
}
packages/types/src/base.ts:190
export interface ComponentRendererProps< TSchema extends BaseSchema = BaseSchema > {
schema: TSchema;
[key: string]: any;
}
Same name, both exported from their package entry (core/src/index.ts:9 re-exports it alongside SchemaNode), from two packages the same consumers import together — the identical shape #4580 describes for SchemaNode, and it sits two lines below it in one file and seven lines below it in the other. They are not the same type: one is generic and constrains schema to the object form (TSchema extends BaseSchema), the other is non-generic and types schema as SchemaNode.
Why it is observation-class rather than a defect today
Nothing imports it. A grep across packages and apps for ComponentRendererProps finds only the two declarations, core's entry re-export, and the built .d.ts of each — zero source consumers on either side. So it has no live collision to cause, which is exactly why #4548's canary never measured one for this name while measuring 19 for SchemaNode.
That also makes it cheap to get wrong later: the day someone does import it, which declaration they get depends on which package they reached for, and the two disagree about whether a primitive node is admissible.
Interaction with #4580
Worth noting for whoever takes #4580: core's ComponentRendererProps.schema is typed SchemaNode, so if core's SchemaNode becomes a re-export of types' union, this interface's schema silently widens from "object with a required type" to "object or string | number | boolean | null | undefined" as a side effect. Harmless while it has no consumers, but it is a published surface changing without a card naming it — worth folding into the same decision rather than discovering afterwards.
Refs #4580, #4548, PR #4593.
Generated by Claude Code
Found while measuring #4580 (the
SchemaNodereconciliation, PR #4593). Filed rather than fixed — #4580's scope isSchemaNode, and this is a second, independent pair sitting in the same two files.The pair
packages/core/src/types/index.ts:18packages/types/src/base.ts:190Same name, both exported from their package entry (
core/src/index.ts:9re-exports it alongsideSchemaNode), from two packages the same consumers import together — the identical shape #4580 describes forSchemaNode, and it sits two lines below it in one file and seven lines below it in the other. They are not the same type: one is generic and constrainsschemato the object form (TSchema extends BaseSchema), the other is non-generic and typesschemaasSchemaNode.Why it is observation-class rather than a defect today
Nothing imports it. A grep across
packagesandappsforComponentRendererPropsfinds only the two declarations, core's entry re-export, and the built.d.tsof each — zero source consumers on either side. So it has no live collision to cause, which is exactly why #4548's canary never measured one for this name while measuring 19 forSchemaNode.That also makes it cheap to get wrong later: the day someone does import it, which declaration they get depends on which package they reached for, and the two disagree about whether a primitive node is admissible.
Interaction with #4580
Worth noting for whoever takes #4580: core's
ComponentRendererProps.schemais typedSchemaNode, so if core'sSchemaNodebecomes a re-export of types' union, this interface'sschemasilently widens from "object with a requiredtype" to "object orstring | number | boolean | null | undefined" as a side effect. Harmless while it has no consumers, but it is a published surface changing without a card naming it — worth folding into the same decision rather than discovering afterwards.Refs #4580, #4548, PR #4593.
Generated by Claude Code