Skip to content

feat(language-core): check typed slot children and infer render types - #6206

Draft
ubugeeei wants to merge 6 commits into
vuejs:v3.4from
ubugeeei:feat/typed-slot-children
Draft

ubugeeei wants to merge 6 commits into
vuejs:v3.4from
ubugeeei:feat/typed-slot-children

Conversation

@ubugeeei

@ubugeeei ubugeeei commented Sep 15, 2026

Copy link
Copy Markdown
Member

Implements RFC 734 with an opt-in vueCompilerOptions.strictSlotChildren check. For example:

defineSlots<{
  default(): Renders<typeof Item<number>>[];
}>();

The slot accepts Item children with numeric values, including SFC wrappers that render them. A string-valued Item, an unrelated component, or a native element produces a template diagnostic. Imported aliases and component generic arguments are resolved by TypeScript.

Renders<typeof Comp> serves the same purpose as Flow's renders Comp. | undefined allows empty content, arrays allow repeated children, and a second type argument can constrain bound props.

This Draft targets v3.4. The documentation PR should land with the tooling release.

Details

  • Checks native elements, text, component props, arrays, and ordered tuples. Unions of complete tuples retain their order and count constraints.
  • Checks every conditional path, including a missing else. Dynamic slot names and component choices must satisfy each possible slot contract.
  • Follows wrapper roots, supplied slots, and empty-slot fallbacks. Conditional named slots retain which names exist together.
  • Exports distinct SFC identities and root types in declarations so consumers retain generic and wrapper checks.
  • Uses the existing localTypes.ts / defineHelper mechanism to emit referenced slot helpers and their dependencies.

The option defaults to false; strictTemplates does not enable it. Renders is exported by vue-component-type-helpers. No Vue runtime or SFC compiler changes are required.

Root inference requires generated SFC metadata. Components without it use TypeScript's structural compatibility, and arbitrary render functions do not expose their roots. Unresolved wrapper cycles fail restricted checks. TypeScript's instantiation limits still apply. Implementation notes describe the type model and regression coverage.

Validation

CI passes on Linux, macOS, and Windows at 0e9950245.

  • pnpm test: 233 passed, 4 skipped; 48 suites passed, 1 skipped. Also passed on Node 24 with a 2 GB heap limit.
  • pnpm run lint: 191 passed. Changed files formatted with the root format script.
  • Fixtures check accepted cases, then remove expected-error directives to assert diagnostic codes and source locations. The same fixtures are checked with the option disabled.
  • Declaration output is checked by plain TypeScript with skipLibCheck: false, without Volar ambient helpers, and consumed by a separate Vue project.

A separate preparatory commit pins VS Code grammar URLs to the revision matching the existing checksums and removes an unnecessary assertion that failed lint on the base branch.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant