vuejs / vuejs/core

exactOptionalPropertyTypes breaks v-bind with defineProps in some cases

Open
#14,366 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

scope: types
Dominant language
TypeScript
Stars
54.4k
Forks
9.2k
Avg merge
1d 5h
Merged PRs (30d)
140

Description

Vue version

3.5.27

Link to minimal reproduction

https://github.com/DerZade/vue-tsc-exact-optional-prop-types-error

Steps to reproduce
  1. Create a project with npm create vue@latest
  2. Turn on exactOptionalPropertyTypes in your tsconfig.app.json
  3. Create a component with a separate type of defineProps:
    <template><!-- irrelevant --></template>
    
    <script lang="ts" setup>
    export type CompProps = {
        somethingOptional?: string; // the optional (?) is important
    };
    
    const props = defineProps<CompProps>();
    </script>
    
  4. Create wrapper component for first component and re-use the props type in its defineProps:
    <template>
        <Comp v-bind="props" /> <!-- This v-bind will error -->
    </template>
    
    <script setup lang="ts">
    import Comp from './Comp.vue';
    import type { CompProps } from './Comp.vue';
    
    const props = defineProps<CompProps>();
    </script>
    
What is expected?

vue-tsc not to error :D

What is actually happening?
$ npm run type-check

> vue-tsc-exact-optional-prop-types@0.0.0 type-check
> vue-tsc --build

src/App.vue:3:6 - error TS2379: Argument of type '{ somethingOptional: string; }' is not assignable to parameter of type '{ readonly somethingOptional?: string; } & VNodeProps & AllowedComponentProps & ComponentCustomProps & Record<string, unknown>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
  Type '{ somethingOptional: string; }' is not assignable to type '{ readonly somethingOptional?: string; }' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
    Types of property 'somethingOptional' are incompatible.
      Type 'string | undefined' is not assignable to type 'string'.
        Type 'undefined' is not assignable to type 'string'.

3     <Comp v-bind="props" />
       ~~~~


Found 1 error.
System Info
System:
    OS: Linux 6.18 Fedora Linux 42 (Workstation Edition)
    CPU: (16) x64 AMD Ryzen 7 7840U w/ Radeon  780M Graphics
    Memory: 44.07 GB / 60.62 GB
    Container: Yes
    Shell: 5.2.37 - /bin/bash
  Binaries:
    Node: 22.19.0 - /home/jonas/.nvm/versions/node/v22.19.0/bin/node
    Yarn: 1.22.22 - /usr/local/sbin/yarn
    npm: 11.7.0 - /home/jonas/.nvm/versions/node/v22.19.0/bin/npm
    pnpm: 10.12.1 - /home/jonas/.local/share/pnpm/pnpm
    bun: 1.1.42 - /home/jonas/.bun/bin/bun
    Deno: 2.5.4 - /home/jonas/.deno/bin/deno
  Browsers:
    Chrome: 144.0.7559.59
    Firefox: 147.0
    Firefox Developer Edition: 147.0
Any additional comments?

This might be a duplicate of https://github.com/vuejs/core/issues/6532 and I reported this issue initially as https://github.com/vuejs/language-tools/issues/5947#

Looks like the defineProps<T> returns the optional properties of T with | undefined instead of keeping it actually optional with the ?. So { foo?: string } becomes { foo: string | undefined }, which will make it incompatible if exactOptionalPropertyTypes is enabled, therefore it is not accepted in the v-bind.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked minimal reproduction: enable exactOptionalPropertyTypes in tsconfig.app.json and reproduce the v-bind error in App.vue using the Comp.vue and defineProps examples. Trace the prop types produced for defineProps and consumed by v-bind, then compare core issue #6532 and language-tools issue #5947. Done means the reproduction type-checks without the reported error and has regression coverage.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.