Skip to content

exactOptionalPropertyTypes breaks v-bind with defineProps in some cases #14366

@DerZade

Description

@DerZade

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 #6532 and I reported this issue initially as vuejs/language-tools#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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions