vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.4k stars 8.29k forks source link

Typescript doesn't compile if component has no props #6441

Closed davidgiga1993 closed 2 years ago

davidgiga1993 commented 2 years ago

Vue version

3.2.37

Link to minimal reproduction

https://github.com/davidgiga1993/vue-ts-issue

Steps to reproduce

  1. Create a new project using typescript as preset

    vue create sample
    cd sample
    npm run serve
  2. Edit the default HelloWorld component: We remove the default msg property and add a single data item which gets used in a computed property

    export default defineComponent({
    name: 'HelloWorld',
    data(){
    return {
      dataTest: false,
    }
    },
    computed: {
    test() {
      return this.dataTest;
    }
    }
    });
  3. Run the project: npm run serve

What is expected?

No errors, the component should just work

What is actually happening?

As soon as the component has no property anymore, any references to items defined in the data section doesn't work anymore:

ERROR in src/components/HelloWorld.vue:51:19
TS2339: Property 'dataTest' does not exist on type 'CreateComponentPublicInstance<{ [x: string & `on${string}`]: ((...args: any[]) => any) | undefined; } | { [x: string & `on${string}`]: ((..
.args: never) => any) | undefined; }, {}, {}, {}, {}, ComponentOptionsMixin, ... 11 more ..., {}>'.
  Property 'dataTest' does not exist on type '{ $: ComponentInternalInstance; $data: {}; $props: { [x: string & `on${string}`]: ((...args: any[]) => any) | undefined; } | { [x: string & `on${
string}`]: ((...args: never) => any) | undefined; }; ... 10 more ...; $watch(source: string | Function, cb: Function, options?: WatchOptions<...> | undefined): WatchStopHan...'.
    49 |   computed: {
    50 |     test() {
  > 51 |       return this.dataTest;
       |                   ^^^^^^^^
    52 |     }
    53 |   }
    54 | });

It doesn't matter which prop is set, you can just add a dummy

props: {
    anything: String
  },

and it will start working again

System Info

System:
    OS: Windows 10 10.0.19044
    CPU: (16) x64 11th Gen Intel(R) Core(TM) i7-11850H @ 2.50GHz
    Memory: 10.46 GB / 31.71 GB
  Binaries:
    Node: 16.14.0 - C:\Dev\node\node.EXE
    npm: 8.5.1 - C:\Dev\node\npm.CMD
  Browsers:
    Edge: Spartan (44.19041.1266.0), Chromium (104.0.1293.47)
    Internet Explorer: 11.0.19041.1566
  npmPackages:
    vue: ^3.2.13 => 3.2.37

Any additional comments?

No response

LinusBorg commented 2 years ago

your likely undelying problem is that you don't annotate the computed property's return type, which is required when using Options API & TS.

https://vuejs.org/guide/typescript/options-api.html#typing-computed-properties

Can'T 100% verify as I can't run the reproduction right now, but I'm willing to bet that it's this.

davidgiga1993 commented 2 years ago

your likely undelying problem is that you don't annotate the computed property's return type, which is required when using Options API & TS.

https://vuejs.org/guide/typescript/options-api.html#typing-computed-properties

Can'T 100% verify as I can't run the reproduction right now, but I'm willing to bet that it's this.

I just checked and you're correct, it does work when I provide a type for the computed property. However: Why does it work when I have at least one - non related - property set? I would expect the error to either appear always or never since the prop has nothing to do with the rest.

LinusBorg commented 2 years ago

That's kinda hard to figure out or explain. The typings for Option API's this are inherently circular: the type if this depends on the return values of options like the computed properties, as those become properties on this, but the return type of your un-annotated computed property depends on the this type.

This generates a wide range of possible combinations of things that inherit from other things in a circular fashion which usually break the types if return annotations are not provided, but sometimes, TS can figure it out.