Skip to content

fix(types): support exact optional public props#14965

Open
ifer47 wants to merge 2 commits into
vuejs:mainfrom
ifer47:fix/exact-optional-public-props
Open

fix(types): support exact optional public props#14965
ifer47 wants to merge 2 commits into
vuejs:mainfrom
ifer47:fix/exact-optional-public-props

Conversation

@ifer47

@ifer47 ifer47 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

This PR fixes the exactOptionalPropertyTypes regression around defineProps spreads by widening the public $props surface for optional keys while keeping internal toRefs behavior intact. It adds a dedicated exact-optional dts fixture and tsconfig, and passes pnpm test-dts-only.

Fixes #14366.

Summary by CodeRabbit

  • Tests

    • Added new type-checking coverage for Vue component optional props when exactOptionalPropertyTypes is enabled.
    • Extended the DTS-only test run to include an additional strict TypeScript compilation pass.
  • Chores / Type Improvements

    • Improved the public-facing component $props typing to better preserve optional-prop behavior under strict TypeScript settings, including components with default prop values.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Introduces a LooseOptional<T> type helper in componentPublicInstance.ts that remaps optional prop keys to allow undefined, then applies it to ComponentPublicInstance.$props. Adds a new tsconfig enabling exactOptionalPropertyTypes and a matching type-test file, wired into the test-dts-only npm script.

Changes

exactOptionalPropertyTypes $props fix

Layer / File(s) Summary
LooseOptional helper and $props update
packages/runtime-core/src/componentPublicInstance.ts
Adds LooseOptional<T> generic that maps optional prop keys to T[K] | undefined, with an IfAny fallback. Updates ComponentPublicInstance.$props on both sides of the MakeDefaultsOptional conditional to wrap P with LooseOptional<P>.
Type test infrastructure
packages-private/dts-test/tsconfig.exactOptionalPropertyTypes.json, packages-private/dts-test/exactOptionalPropertyTypes.test-d.tsx, package.json
Adds a dedicated tsconfig extending tsconfig.test.json with exactOptionalPropertyTypes: true. New type test defines Child and WithDefault Vue components with optional foo props and asserts JSX.Element for spread props and explicit foo={undefined} scenarios. Updates test-dts-only script to run the new tsconfig project.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • vuejs/core#12870: Both PRs modify TypeScript typing for component instance $props—this PR loosens optional prop keys via LooseOptional<P> in componentPublicInstance.ts, while that PR addresses component instance resolution in component.ts.

Suggested labels

scope: types

Suggested reviewers

  • jh-leong
  • edison1105
  • KazariEX

Poem

🐇 A prop of type optional, uncertain and wide,
undefined once barred — now welcomed inside.
LooseOptional hops in with a wiggle and glee,
spreading its types so the JSX runs free.
No more strict errors to ruffle this hare! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding support for exact optional properties in the public prop types, which aligns with the primary objective of fixing a regression related to exactOptionalPropertyTypes.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


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 Jun 15, 2026

Copy link
Copy Markdown

Open in StackBlitz

@vue/compiler-core

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

@vue/compiler-dom

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

@vue/compiler-sfc

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

@vue/compiler-ssr

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

@vue/reactivity

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

@vue/runtime-core

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

@vue/runtime-dom

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

@vue/server-renderer

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

@vue/shared

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

vue

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

@vue/compat

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

commit: bc2d402

@github-actions

Copy link
Copy Markdown

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 106 kB 40.2 kB 36.1 kB
vue.global.prod.js 164 kB 60.2 kB 53.5 kB

Usages

Name Size Gzip Brotli
createApp (CAPI only) 48.8 kB 19 kB 17.4 kB
createApp 56.9 kB 22 kB 20.1 kB
createSSRApp 61.2 kB 23.8 kB 21.7 kB
defineCustomElement 63.1 kB 23.9 kB 21.8 kB
overall 71.7 kB 27.4 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.

Thanks for the fix. I found one remaining exactOptionalPropertyTypes hole around defaulted props.

Comment thread packages/runtime-core/src/componentPublicInstance.ts Outdated
@ifer47

ifer47 commented Jun 27, 2026

Copy link
Copy Markdown
Contributor Author

@edison1105 The remaining defaulted-props case was addressed in bc2d402 and the review thread is resolved. CI is green now. Could you take another look when you have a chance? Thanks!

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.

exactOptionalPropertyTypes breaks v-bind with defineProps in some cases

2 participants