Skip to content

fix(types): preserve slot prop requiredness in SlotsType - #15109

Closed
KazariAI wants to merge 2 commits into
vuejs:mainfrom
KazariAI:fix/optional-slot-props
Closed

fix(types): preserve slot prop requiredness in SlotsType#15109
KazariAI wants to merge 2 commits into
vuejs:mainfrom
KazariAI:fix/optional-slot-props

Conversation

@KazariAI

@KazariAI KazariAI commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • prevent optional slot keys from making object-style slot props optional
  • document the default TypeScript limitation around explicit undefined in optional properties
  • restore regression coverage for optional slots whose props explicitly include undefined

This pull request was created with assistance from a code agent.

Summary by CodeRabbit

  • Bug Fixes
    • Improved TypeScript slot type inference for components with optional and undefined slot definitions.
    • Refined function-style slot argument typing so requiredness and non-undefined constraints align with the expected slot props.
    • Tightened type assertions for optional slot invocation (including optional-scoped cases) to prevent misleading or overly-permissive errors.
  • Documentation
    • Added clarification on how optional object-style slot props behave when strict optional property typing is disabled.
  • Tests
    • Updated type-level tests to reflect the revised optional/undefined slot behavior.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Function-valued slot types now use required property handling during unwrapping. Type tests update optional slot prop assertions and enforce non-undefined scopes where required.

Changes

Slot typing

Layer / File(s) Summary
Update slot type mapping and declaration contracts
packages/runtime-core/src/componentSlots.ts, packages-private/dts-test/defineComponent.test-d.tsx
UnwrapSlotsType uses Required<T>[K] for function-valued slots, with documentation and tests covering optional, undefined-scope, and required-scope invocation behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • vuejs/core#15107: Updates related slot typing coverage and optional or undefined slot invocation assertions.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: preserving requiredness for slot props in SlotsType.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@vue/compiler-core

pnpm add https://pkg.pr.new/@vue/compiler-core@15109
npm i https://pkg.pr.new/@vue/compiler-core@15109
yarn add https://pkg.pr.new/@vue/compiler-core@15109.tgz

@vue/compiler-dom

pnpm add https://pkg.pr.new/@vue/compiler-dom@15109
npm i https://pkg.pr.new/@vue/compiler-dom@15109
yarn add https://pkg.pr.new/@vue/compiler-dom@15109.tgz

@vue/compiler-sfc

pnpm add https://pkg.pr.new/@vue/compiler-sfc@15109
npm i https://pkg.pr.new/@vue/compiler-sfc@15109
yarn add https://pkg.pr.new/@vue/compiler-sfc@15109.tgz

@vue/compiler-ssr

pnpm add https://pkg.pr.new/@vue/compiler-ssr@15109
npm i https://pkg.pr.new/@vue/compiler-ssr@15109
yarn add https://pkg.pr.new/@vue/compiler-ssr@15109.tgz

@vue/reactivity

pnpm add https://pkg.pr.new/@vue/reactivity@15109
npm i https://pkg.pr.new/@vue/reactivity@15109
yarn add https://pkg.pr.new/@vue/reactivity@15109.tgz

@vue/runtime-core

pnpm add https://pkg.pr.new/@vue/runtime-core@15109
npm i https://pkg.pr.new/@vue/runtime-core@15109
yarn add https://pkg.pr.new/@vue/runtime-core@15109.tgz

@vue/runtime-dom

pnpm add https://pkg.pr.new/@vue/runtime-dom@15109
npm i https://pkg.pr.new/@vue/runtime-dom@15109
yarn add https://pkg.pr.new/@vue/runtime-dom@15109.tgz

@vue/server-renderer

pnpm add https://pkg.pr.new/@vue/server-renderer@15109
npm i https://pkg.pr.new/@vue/server-renderer@15109
yarn add https://pkg.pr.new/@vue/server-renderer@15109.tgz

@vue/shared

pnpm add https://pkg.pr.new/@vue/shared@15109
npm i https://pkg.pr.new/@vue/shared@15109
yarn add https://pkg.pr.new/@vue/shared@15109.tgz

vue

pnpm add https://pkg.pr.new/vue@15109
npm i https://pkg.pr.new/vue@15109
yarn add https://pkg.pr.new/vue@15109.tgz

@vue/compat

pnpm add https://pkg.pr.new/@vue/compat@15109
npm i https://pkg.pr.new/@vue/compat@15109
yarn add https://pkg.pr.new/@vue/compat@15109.tgz

commit: 7afe925

@github-actions

Copy link
Copy Markdown

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 107 kB 40.5 kB 36.3 kB
vue.global.prod.js 166 kB 60.6 kB 53.8 kB

Usages

Name Size Gzip Brotli
createApp (CAPI only) 49.2 kB 19.1 kB 17.5 kB
createApp 57.3 kB 22.2 kB 20.3 kB
createSSRApp 61.9 kB 24.1 kB 21.9 kB
defineCustomElement 63.5 kB 24.1 kB 22 kB
overall 71.9 kB 27.5 kB 25 kB

@edison1105 edison1105 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found one blocking type regression.

[K in keyof T]: NonNullable<T[K]> extends (...args: any[]) => any
? T[K]
: Slot<T[K]>
: Slot<Required<T>[K]>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Required<T>[K] also removes an explicitly declared undefined from an optional property when exactOptionalPropertyTypes is disabled, as it is in packages-private/dts-test/tsconfig.test.json. For optionalUndefinedScope?: undefined | { data: string }, this makes both slots.optionalUndefinedScope?.() and slots.optionalUndefinedScope?.(undefined) fail. The PR removes the existing test that covered exactly this combination, which contradicts the stated goal of preserving empty and undefined calls when slot props explicitly include undefined. Please restore that coverage and preserve this behavior, or explicitly narrow and document the supported contract; enabling exactOptionalPropertyTypes only in the test config would not protect consumers using the default setting.

@KazariAI
KazariAI force-pushed the fix/optional-slot-props branch from a1ed2d7 to 50e3fb0 Compare July 21, 2026 01:12
@KazariAI

Copy link
Copy Markdown
Contributor Author

Thanks for catching this. Closing because with exactOptionalPropertyTypes disabled, TypeScript cannot distinguish an optional property from one that explicitly includes undefined, so the intended behavior cannot be preserved for default consumers.

@KazariAI KazariAI closed this Jul 21, 2026
@KazariAI
KazariAI deleted the fix/optional-slot-props branch July 21, 2026 01:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants