Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using expose in options API breaks vue-tsc typing in templates in Vue 3.5 #5069

Open
catrope opened this issue Dec 18, 2024 · 2 comments
Open
Labels
bug Something isn't working good reproduction ✨ This issue provides a good reproduction, we will be able to investigate it first 🔨 p3-minor-bug

Comments

@catrope
Copy link

catrope commented Dec 18, 2024

Vue - Official extension or vue-tsc version

2.1.10

VSCode version

N/A

Vue version

3.5.13

TypeScript version

5.7.2

System Info

System:
    OS: Linux 6.8 Ubuntu 24.04.1 LTS 24.04.1 LTS (Noble Numbat)
    CPU: (12) x64 12th Gen Intel(R) Core(TM) i7-1265U
    Memory: 34.84 GB / 46.72 GB
    Container: Yes
    Shell: 5.2.21 - /bin/bash
  Binaries:
    Node: 20.16.0 - ~/.nvm/versions/node/v20.16.0/bin/node
    npm: 10.8.1 - ~/.nvm/versions/node/v20.16.0/bin/npm
  Browsers:
    Chrome: 131.0.6778.139
    Chromium: 128.0.6613.84

package.json dependencies

No response

Steps to reproduce

Write a component using the Option API, and use expose to expose some properties but not others. For example:

<template>
    <p>{{ msg }}</p>
    <input v-model="msg">
    <p>{{ msg2 }}</p>
    <input v-model="msg2">
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';

export default defineComponent( {
    expose: [ 'msg' ],
    setup() {
        const msg = ref( 'hello' );
        const msg2 = ref( 'world' );
        return { msg, msg2 };
    }
} );
</script>

What is expected?

This should pass, which it did in Vue 3.4.x

What is actually happening?

In Vue 3.5.x, this causes the following TypeScript error (both in VSCode and when running vue-tsc on the command line):

Property 'msg2' does not exist on type 'CreateComponentPublicInstanceWithMixins<Readonly<{}>, { msg: Ref<string, string>; msg2: Ref<string, string>; }, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 17 more ..., {}>'.

The same thing happens for everything (refs returned by setup, but also props and methods) that is not listed in the expose array. If you remove the expose array altogether, the error goes away.

Link to minimal reproduction

No response

Any additional comments?

It appears that Vue 3.5.x changed something that led vue-tsc to type-check the template using the public-facing version of the component instance (which only contains exposed properties) when it should be using the internal-facing version of the component instance (which contains all properties returned from setup, as well as props etc).

I tried different versions of Vue, and it appears this issue was introduced between Vue 3.4.38 and 3.5.0-alpha.1, which makes me suspect vuejs/core@75c8cf6 might have caused this.

@KazariEX KazariEX added bug Something isn't working good reproduction ✨ This issue provides a good reproduction, we will be able to investigate it first 🔨 p3-minor-bug and removed pending triage labels Dec 18, 2024
@catrope
Copy link
Author

catrope commented Dec 18, 2024

It looks like the type returned by defineComponent() changed between Vue 3.4.38 and Vue 3.5.0. Consider the following code:

const Component = defineComponent( {
  setup() {
    const msg = ref( 'hello' );
    const msg2 = ref( 'world' );
    return { msg, msg2 };
  },
  expose: [ 'msg' ]
} );

const instance = new Component();
console.log( instance.msg );
console.log( instance.msg2 );

(note this code doesn't actually run, it throws a runtime error because Component isn't actually a constructor despite the TypeScript type of defineComponent claiming that it should be -- but it's instructive for TypeScript purposes)

In Vue 3.4.x, this code passes TypeScript, but in Vue 3.5.x TypeScript complains that instance doesn't have a property named msg2. This demonstrates that in Vue 3.4.x, the return type of defineComponent includes non-exposed properties, but in Vue 3.5.x it doesn't.

wmfgerrit pushed a commit to wikimedia/design-codex that referenced this issue Dec 20, 2024
We can't update to 3.5.x yet because of
vuejs/language-tools#5069 , but for newer
versions of TypeScript to work we do need the types for the toggle event
on `<details>` to be correct, and 3.4.28 fixes that.

Change-Id: I9c90a90b58076e18fb1dc594effa73662123568d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working good reproduction ✨ This issue provides a good reproduction, we will be able to investigate it first 🔨 p3-minor-bug
Projects
None yet
Development

No branches or pull requests

2 participants