Skip to content

spec(types,react,core): every node slot is SchemaNode (= BaseSchema), so after objectui#8347's removal an inline child carrying its own type's keys stops compiling; type node slots and SchemaRenderer's schema prop as the declared node union #11466

Description

@objectstack-fleet

Blocked-by: #11543

This card carries objectui#8347's F1 half: the TypeScript type of a node slot and of SchemaRenderer's schema prop. objectui#8347 keeps the removal itself and everything its fork ACCEPT lists for the last PR.

Filing-gate category: ① — a named landing point (SchemaNode in @object-ui/types, SchemaRenderer's schema prop in @object-ui/react, @object-ui/core's schema builder), measured reach, and named producers, ordered by the objectui#7927 ruling's step 1. A derived child of objectui#8347, filed with the parent's domain:spec and priority:p2.
Reader: the domain:spec @ objectui seat (objectui#10217) dispatches it, and an os-dev executes it.
Parent: objectui#8347, which is pm:blocked until this card and its two siblings land.

What was measured (objectui#8347's P1 report 5953663875, at main 5988b6b53)

SchemaNode is BaseSchema | string | number | boolean | null | undefined (packages/types/src/base.ts, read on origin/main), and every node slot (children, trigger, content, a view's schema) uses it. SchemaRenderer's schema prop is BaseSchema | AuthoringNode | string | null | undefined. With BaseSchema's index signature deleted alone:

  • an inline child that carries its own type's keys (a text node's content, a statistic's value, a button's variant) stops compiling, and per-child satisfies TextSchema does not help, because the slot still excess-checks the literal against BaseSchema (measured by a type probe);
  • 8 test and example literals: types page-body-arity-8310 ×3, overlay-trigger-union-7081 ×2, @object-ui/core's schema builder ×2 (.child() takes BaseSchema), and the types example's HeaderBarSchema cast ×1;
  • 17 doc diagnostics in check:doc-snippets: schema-renderer.mdx ×3 (including a custom widget's customProp), architecture.md, quick-start.md, schema-playground.md, schema-rendering.md, enhanced-actions.mdx, building-crud-app.md and data-source.md (objectName on a detail node), the objectos-integration.mdx page template, the plugin-detail README ×3, the plugin-view README ×2, and the types README's crumbs;
  • check:doc-examples: SchemaNode's own docblock example (content on a BaseSchema literal).

reach: the published SchemaNode type and the SchemaRenderer prop. The named producers are the getting-started docs above and @object-ui/core's .child(). Today they compile only through the index signature.

Seat ruling: A, conditioned on a premise (inside the maintainer's veto window)

Governing text: the objectui#5250 ruling as objectui#8347's body quotes it: "the TypeScript side gets the matching authoring types without the [key: string]: any index signature ... so an invented or misspelled key is distinguishable from a declared one at the authoring site". A nested child is an authoring site.

  • ① The ruling: node slots (the object arm of SchemaNode) and SchemaRenderer's schema prop take the discriminated union of the declared node types, keyed by type (AnySchema ∪ AuthoringNode).
    • Option B (keep BaseSchema and make every nested node a pre-typed constant) pushes TypeScript authors to as casts at the authoring site, which is tolerance where the error should be refused.
    • Option C (an explicit open record for children only) re-creates the index signature one level down, which the objectui#7927 removal ruling refuses.
  • ② The premise, which the implementer measures first, before any other edit. Under objectui#8347's P1 mutation (the six BaseSchema lines deleted alone), with a throwaway probe file compiled by tsc -p tsconfig.test.json:
    • (a) an inline child of a declared type with a misspelled key is REFUSED, and the correctly spelled control compiles, both at a nested slot and at the SchemaRenderer prop;
    • (b) a node of a registered custom type (the schema-renderer.mdx custom widget is the named instance) stays authorable through a mechanism that does NOT let a declared type's literal escape its own arm's excess check;
    • (c) the type-check time of the types, react and components programs is reported before and after, as a number. That is evidence for the seat, not a stop condition.
  • ③ The prohibition: if (a) or (b) fails, report the fork with the probe evidence. ⛔ Do not fall back silently to B or C, ⛔ do not add an index signature or a type: string catch-all arm at the slot, and ⛔ do not grow the card.

Constraints

  • Every edit here must compile WITH the signature still present, so this card lands on its own and main stays green. The removal stays objectui#8347's.
  • The listed tests and docs move with the type: a doc block whose example now fails compiles against the new slot type, or is re-annotated with the declared node type.
  • The compile-fail pin rides here: a misspelled key on a nested child is refused under the P1 mutation (assert it with the mutation applied in a probe, or with a test that declares the stripped shape locally). The correct spelling still compiles.
  • Clause-② is stated at claim from the actual accept-set change. With the signature present, a member union of index-signature types accepts what BaseSchema accepts today.

Dedupe

REST list of objectui's 600 most recently updated issues and PRs, open and closed (back to 2026-09-28T12:31Z), grepped locally on 2026-10-02: SchemaNode 13 hits, all closed PRs or the closed preparation card objectui#11364; "node slot / nested child type" 6 hits, none open on this question (objectui#11069 is the validate wiring); control objectui 589.

Dedupe words: SchemaNode slot union · inline child excess property BaseSchema · SchemaRenderer schema prop node union

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanepriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions